event or mousePressEvent functions works for inside of a widget but I want to catch when clicked on a titleBar (upper part of menuBar, contains close button etc.)
How ca
You can override nativeEvent, then get mouse position to compare with geometry (exclude window frame) and frameGeometry (include window frame) to detect if it hits title bar or not
bool MyClass::nativeEvent(const QByteArray & eventType, void * message, long * result)
{
MSG* msg = (MSG*)(message);
if (msg->message == WM_NCLBUTTONDOWN)
{
int mouseX = GET_X_LPARAM(msg->lParam);
int mouseY = GET_Y_LPARAM(msg->lParam);
QRect frame = frameGeometry();
QRect content = geometry();
qDebug() << "mouseX: " << mouseX << "mouseY:" << mouseY;
qDebug() << "frame: " << frame;
qDebug() << "content: " << content;
if (mouseY < content.y() && mouseY >= frame.y())
{
qDebug() << "Hit title bar";
}
}
*result = 0;
return false;
}
Here's the PyQt implementation.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import ctypes.wintypes
import logging
from win32con import *
import win32api
class W(QTabWidget):
def nativeEvent(self, eventType, message):
click_menu = QMenu(self)
click_menu.addAction("Yay")
try:
msg = ctypes.wintypes.MSG.from_address(message.__int__())
except:
logging.error("", exc_info=True)
if eventType == "windows_generic_MSG":
if msg.message == WM_NCLBUTTONDOWN:
mouse_x = win32api.LOWORD(msg.lParam)
mouse_y = win32api.HIWORD(msg.lParam)
frame = self.frameGeometry()
content = self.geometry()
print(mouse_x, mouse_y, frame, content)
if mouse_y < content.y() and mouse_y >= frame.y():
click_menu.exec_(QPoint(mouse_x, mouse_y))
return False, 0
app = QApplication([])
w = W()
w.resize(1000,100)
w.move(0,0)
w.show()
app.exec_()
One thing I can't figure out about this, what happens to my menu if I click the titlebar again without clicking the menu. The menu disappears, which is then allows me to move the titlebar when clicking - which is good...but I can't reliably bring the menu back up