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;
}
Related
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;
}
I have a subclass of QGraphicsView that should accept two kinds of mouse events: drag and drop for scrolling and simple clicks for item selection/highlight.
So I use
setDragMode(QGraphicsView::ScrollHandDrag);
to enable scrolling the view with the "Hand". And I have a function like this:
void GraphView::mouseReleaseEvent(QMouseEvent* e)
{
if (e->button() == Qt::LeftButton)
emit leftClicked(mapToScene(e->pos()));
else
emit rightClicked(mapToScene(e->pos()));
QGraphicsView::mouseReleaseEvent(e);
}
which creates signal whenever the user clicks on the scene.
However, the problem is: when I stop dragging and release the mouse button, the mouseReleaseEvent function is called, and if the cursor happens to be over some element of the scene, it will get highlighted.
How can I changed the mouseReleaseEvent function so that the signals are created only if there was no previous drag of the mouse?
If you use mousePress and mouseMove in combination with mouseRelease, then you can determine what mouse action the user just performed.
If you have mousePress then mouseRelease, then it must be a simple click.
If you have mousePress, mouseMove, and then mouseRelease, then it must be a drag.
The Qt documentation contains an example of interpreting combinations of mouse events in action in a scribbling program.
http://doc.qt.io/qt-4.8/qt-widgets-scribble-example.html
You can extend the principle to something like this:
private bool MyWidget::dragging = false;
private bool MyWidget::pressed = false;
void MyWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
pressed=true;
}
QGraphicsView::mousePressEvent(event)
}
void MyWidget::mouseMoveEvent(QMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton) && pressed)
{
dragging=true;
}
QGraphicsView::mouseMoveEvent(event)
}
void MyWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && pressed) {
pressed = false;
if (dragging)
{
dragging = false;
}
else
{
// plain mouse click
// do something here
}
}
QGraphicsView::mouseReleaseEvent(event)
}
Note that this does not address edge cases where a user's mouse action is performed only partially inside the widget. I must also admit that I am relatively new to Qt and have not yet used ScrollHandDrag, but this is how one would go about identifying a certain combination of mouse events.
I want to generate the right click menu from the entry of a QTreeView. Currently I tried this, but I don't want the whole treeView to generate the right click and then me to filter the position on which the mouse is. I want that the signal to be generated from the entry.
connect(mtreeView, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(showContextMenu(const QPoint&)));
Thanks!
Method 1
It is better to use the ContextMenuEvent rather than MouseReleaseEvent as it is a more portable way to trigger the context menu, will support accessibility on certain platforms, etc... The right click is not the only way to open a context menu.
If you do not want to subclass QTreeView , install an event handler from the main window:
ui->myTreeView->installEventFilter(this);
Then handle the event in the main window filterEvent
bool MainWindow::eventFilter(QObject *target, QEvent *event)
{
if (target == ui->myTreeView)
{
QContextMenuEvent* m = dynamic_cast<QContextMenuEvent*>(event);
if (event->type() == QEvent::ContextMenu && e!=0)
{
//Create context menu here
return true;
}
}
return false;
}
Method 2
Change the context menu mode to a signal:
ui->myTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->myTreeView, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(treeCustomMenu(QPoint)));
Then implement your slot:
void MainWindow::treeCustomMenu(const QPoint & pos)
{
//Implement your menu here using myTreeView->itemAt(pos);
}
What I do is to override mouseReleaseEvent and check manually.
void MyTreeView::mouseReleaseEvent(QMouseEvent *e) {
if (e->button() == Qt::RightButton) {
QTreeWidgetItem *item = itemAt(e->pos());
if (item) {
QMenu m;
m.addAction("hello");
m.addAction("world");
QAction *selected = m.exec(mapToGlobal(e->pos()));
if (selected) {
qDebug() << "selected" << selected->text();
}
}
} else {
QTreeView::mouseReleaseEvent(e);
}
}
What you mean by the entry is not represented by a QObject in Qt. Only the item model is a QObject, but the individual tree nodes are not QObjects in Qt item/view system.
Therefore, they cannot emit any signal
I have a long QPushButton (well, a subclass of one) with a menu attached. The drop-down menu indicator is on the right side of the button, but when pressed the menu drops down from the bottom-left corner. This seems to me like it will be clunky and unintuitive for my users.
I've looked through the QPushButton source code, and tried:
this->setLayoutDirection(Qt::RightToLeft);
which did move the menu to the right side, but it broke the button as it also moved the indicator to the left side and made the menus backwards.
Is there another way to make the menu drop from the right side?
It can be done by installing an event filter on the menu used for the QPushButton which moves it when shown.
class rightSideMenuFilter : public QObject
{
public:
bool eventFilter(QObject * obj, QEvent *event)
{
QPushButton* parentButton = dynamic_cast<QPushButton*>(obj->parent());
if (!parentButton)
return false;
QMenu* menu = dynamic_cast<QMenu*>(obj);
if (!menu)
return false;
if (event->type() == QEvent::Show && obj == parentButton->menu())
{
QPoint pos = menu->pos();
qDebug() << "pos" << pos;
pos.setX(pos.x() + parentButton->width() - menu->width());
parentButton->menu()->move(pos);
return true;
}
return false;
}
};
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?