Is there a way for a QToolButton to display its associated QMenu on top of it instead of below?
I have seen this answer which pleased me but it's in Python and I don't really know how to port it properly.
I also took a look at the source code for QMenu but it's quite overwhelming so I don't really know how to tackle this issue.
There also is a little arrow on the button showing that it'll pop down.
This is the very bottom of my window so I'd like it to pop up in case it becomes too big to fit.
You could do it using an event filter:
QMenu* yourMenu;
yourButton->setMenu(yourMenu);
yourMenu->installEventFilter(this);
bool yourClass::eventFilter(QObject * obj, QEvent *event)
{
if (event->type() == QEvent::Show && obj == yourButton->menu())
{
QPoint pos = /*the position expected*/;
yourButton->menu()->move(pos);
return true;
}
return false;
}
To remove the little arrow, add this to your stylesheet:
QToolButton::menu-indicator{
image: none;
}
Related
I've got this test piece of code in mainwindow.cpp:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
qDebug() << QString("Mouse move (%1,%2)").arg(mouseEvent->pos().x()).arg(mouseEvent->pos().y());
}
return false;
}
I just want to get mouse position when clicked, and send the coordinates to another thread with an OpenCV loop that'll pull HSV information and do things accordingly. I'm using mouse over just for testing.
The problem is that I have no idea how to attach this (tracking, clicking) to a QLabel labelKalibracja, one I use to display video frames, instead of the whole window.
ui->labelKalibracja->installEventFilter(this);
is supposed to work, but doesn't, but
qApp->->installEventFilter(this);
Will make the whole window a mouse track zone.
You should check the object of the event filter :
if (qobject_cast<QLabel*>(obj)==ui->labelKalibracja && event->type() == QEvent::MouseMove)
{
...
}
Now you can make sure that the event is for the label. Note that the event filter could be installed on multiple objects and it's your duty to identify the combination of objects and events.
I have a graphics view and i have set my own function for scrolling by hand drag when the user presses control and mouse clicks.
I have removed the scroll bars but the mouse wheel will still scroll and even scroll past the image that's being displayed in the qGraphicsView showing blank (white) space which my hand drag doesn't.
How do i make it so wheel just straight up does nothing at all?
I know there is a function I can just put in my code without a derived class because I asked this once before and got the right answer but the answer was removed and i hadn't saved the code :(
The below code does nothing even close to the expected functionality, on start up I get the mouse still doing something message and then all clicks and wheel events everything just displays that second message ... so yea not working
bool GUI::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->graphicsView && event->type() == QEvent::GraphicsSceneWheel)
{
std::cout << "Wheel Blocked";
return true;
}
std::cout << "Mouse Wheel still doing something";
return false;
}
and then this code to install the filter
ui->graphicsView->installEventFilter(this);
Install an eventfilter and filter for
QEvent::GraphicsSceneWheel
Create something like this in your app
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->graphicsView->viewport() && event->type() == QEvent::Wheel) {
qDebug() << "SCroll";
return true;
}
return false;
}
and install to your widget.
yourwidget->viewport()->installEventFilter(this);
Edit:
I thought it should work with QEvent::GraphicsSceneWheel. If anyone knows why works with Wheel, please, explain
Also, you can to modify QGraphicsView using inheritance
class MyCustomGraphicsView : public QGraphicsView
{
virtual void wheelEvent ( QWheelEvent * event )
{
//here you can modify wheel-event
}
}
It is easy way, because qt-designer can associate GraphicsView element on your form with your inherited class
How do I left align the QMenu which is created after a button click?
I want the menu to be opened from the left of the button
void MyMenu::cppSlot()
{
QMenu *xmenu = new QMenu;
xmenu->addMenu("A -> Setup");
xmenu->addMenu("B -> Setup");
xmenu->addMenu("C -> Setup");
xmenu->addMenu("D -> Setup");
xmenu->addMenu("E -> Setup");
xmenu->addMenu("F -> Setup");
xmenu->addMenu("G -> Setup");
xmenu->setFont(QFont ("Courier", 10));
xmenu->setFixedWidth(250);
xmenu->setAutoFillBackground(true);
QPalette palette=xmenu->palette();
palette.shadow();
xmenu->setPalette(palette);
xmenu->show();
}
I know this is an old thread, but I am still putting out the solution for whoever needs help in the future. I had a similar problem where I wanted to open the menu from the bottom-right corner of the button. To implement this, I had to re-write the eventFilter and change the position of the popup menu with respect to the global coordinates. In your case, I am assuming you need it to be on the bottom-left? This is how it should be:
bool MainWindow::eventFilter(QObject *obj, QEvent *event){
if (event->type() == QEvent::Show && obj == ui->myButton->menu()){
ui->myButton->menu()->move(ui->myButton->mapToGlobal(QPoint(0,ui->helpButton->height())));
return true;
}
return false;
}
And somewhere in your code, preferably after you have initialized your QMenu and added it to the button, you will have to add this line:
ui->myButton->setMenu(helpMenu);
helpMenu->installEventFilter(this);
First, read documentation for QMenu here . Read QMenu::exec () and see if you can achieve your requirement. Or else, if you are trying to change the position of menu-indicator sub-control you can use Qt Style Sheets as follows.
QPushButton::menu-indicator {
image: url(menu_indicator.png);
subcontrol-origin: padding;
subcontrol-position: left;
}
Extraneous Information:
I am attempting to build an application using Qt. This application features a QMdiArea and a child-window. My child-window will have a menu which can be integrated into the QMdiArea or segregated and attached to the child itself. Though, this is a bit more detail than needed...
Problem:
I would like my child-widget to have a menu with a shortcut, "CTRL+W." But, because I am using a QMdiArea, the shortcut is already used causing:
QAction::eventFilter: Ambiguous shortcut overload: Ctrl+W
How can I get rid of this shortcut and claim it within my child widget instead?
Update:
Here is what I've tried with no luck:
class MDI : public QMdiArea
{
Q_OBJECT
private:
bool event(QEvent *tEvent)
{
if (tEvent->type() == QEvent::KeyPress)
{
QKeyEvent* ke = static_cast<QKeyEvent*>(tEvent);
if (ke->key()== Qt::Key_W && ke->modifiers() & Qt::ControlModifier)
emit KeyCW();
return true;
}
return QMdiArea::event(tEvent);
}
public:
signals:
void KeyCW();
};
This works if I do something as simple as change Qt::Key_W to Qt::Key_L. The key-combo is received and event is thrown. With W, it just never happens. I've also tried moving event to QMainWindow as well as an eventFilter in the subwindow to QMdiArea. It seems that it is a little overly complicated to do something as simple as remove default key-handlers from within QMdiArea.
You can disable this shortcut like this:
for( QAction *action : subWindow->systemMenu()->actions() ) {
if( action->shortcut() == QKeySequence( QKeySequence::Close ) ) {
action->setShortcut( QKeySequence() );
break;
}
}
You could get rid of the pre-defined close action of the QMdiSubWindow altogether by using Qt::CustomizeWindowHint as additional flag when adding the subwindow.
QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(internalWidget2,
Qt::Widget | Qt::CustomizeWindowHint |
Qt::WindowMinMaxButtonsHint);
Subclass QMdiArea and reimplement keyPressEvent(). That should work.
void keyPressEvent(QKeyEvent* event){
if(event->key() == Qt::Key_W and event->modifiers() & Qt::ControlModifier){
// handle it
}else{
return QMdiArea::keyPressEvent(event);
}
}
You could also use event filters. I don't enough about your class hierarchy, but I hope you get the idea.
bool CustomMdiArea::eventFilter(QObject *object, QEvent *event){
if(object == yourChildWindow && event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_W and keyEvent->modifiers() & Qt::ControlModifier) {
//handle it
return true;
}else{
return false;
}
}
return false;
}
From what I can tell, what I am looking for is not possible short of writing my own MDIArea.
The shortcut is set in QMdiSubWindowPrivate::createSystemMenu() during
the construction of a QMdiSubWindow, I doubt that you can remove it
without having to patch Qt libs.
Hopefully at some point someone will disprove this or QT will make changes. Meanwhile, it looks like we will all need to stay away from these pre-assigned shortcuts.
I was able to work around this by setting the shortcut context for my close action. By setting it to Qt::WidgetShortcut, I no longer get the ambiguous shortcut overload. Here is how I'm setting up my close action now:
closeAction = new QAction(tr("&Close"), this);
closeAction->setShortcut(Qt::CTRL|Qt::Key_W);
closeAction->setShortcutContext(Qt::WidgetShortcut);
connect(closeAction, SIGNAL(triggered()), mdiArea, SLOT(closeActiveSubWindow()));
I want to include a "remove" icon on entries in my QComboBox, but I am having trouble catching the mouse press event. I've tried to catch it on the combobox, and I've tried reimplemting the QIcon class to catch the mousepress there. No dice. Does anybody know how to do this?
-D
I've written code a bit like this, where I wanted to put a tree view inside a combo box and I needed to take an action when the check box on the tree was clicked. What I ended up doing was installing an event filter on the combo box to intercept mouse clicks, figure out where the mouse click was happening, and then take an action. Probably you can do the same kind of thing with your icon. Here is the code:
bool TreeComboBox::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* m = static_cast<QMouseEvent*>(event);
QModelIndex index = view()->indexAt(m->pos());
QRect vrect = view()->visualRect(index);
if(event->type() == QEvent::MouseButtonPress &&
(model()->flags(index) & Qt::ItemIsUserCheckable) &&
vrect.contains(m->pos()))
{
// Your action here
ToggleItem(index);
UpdateSelectionString();
}
if (view()->rect().contains(m->pos()))
skipNextHide = true;
}
return QComboBox::eventFilter(object, event);
}
Maybe you can reimplement QComboBox::mousePressEvent(QMouseEvent *e) and use e.x() together with QComboBox::iconSize() to find if the event occurred over the icon.
This will off cause break if a Qt style decides to switch label and icon position in combo boxes. Don't know if that is possible?