Display tick image on selected QMenu item - c++

I want to show a tick item on selecting particular item from my QMenu.
Currently its showing the menus, but I need to keep a kick also so that next time user can know which is selected before.
QMenu *preferenceMenu = new QMenu();
preferenceMenu = editMenu->addMenu(tr("&Preferences"));
QMenu *Mode1 = new QMenu();
Mode1 = preferenceMenu->addMenu(tr("&Mode 1"));
Mode1->addAction(new QAction(tr("&Menu1"), this));
QMenu *Mode2 = new QMenu();
Mode2 = preferenceMenu->addMenu(tr("&Mode 2"));
Mode2->addAction(new QAction(tr("&Menu2"), this));
Mode2->addAction(new QAction(tr("&Menu3"), this));
On QAction I call slot slotActionTriggered(QAction* actionSelected).
void csTitleBar::slotActionTriggered(QAction* actionSelected)
{
actionSelected->setChecked(true);
}
Here if I select Menu3, a tick also should appear right side of Menu3 and later if I change to Menu2, tick should show on Menu2 and disappear from Menu3.
Please give some idea, whether Qt have some default method to do it or I need to keep widget or image.

You have to make actions checkable via QAction::setCheckable.
QMenu *Mode2 = new QMenu();
Mode2 = preferenceMenu->addMenu(tr("&Mode 2"));
Mode2->addAction(new QAction(tr("&Menu2"), this));
Mode2->actions().back()->setCheckable(true);
Mode2->addAction(new QAction(tr("&Menu3"), this));
Mode2->actions().back()->setCheckable(true);
Also, there is no need to check actions manually in your case, marking them as checkable already does the job.
As mentioned by #G.M., to make some of them mutually exclusive, you have to create a QActionGroup for each set (Menu2 and Menu3 in your case). Just set the action group as the parent of the action or call QActionGroup::addAction.
QMenu* Mode2 = new QMenu();
QActionGroup* Mode2ActionGroup = new QActionGroup(Mode2);
Mode2 = preferenceMenu->addMenu(tr("&Mode 2"));
Mode2->addAction(new QAction(tr("&Menu2"), Mode2ActionGroup));
Mode2->actions().back()->setCheckable(true);
Mode2->addAction(new QAction(tr("&Menu3"), Mode2ActionGroup));
Mode2->actions().back()->setCheckable(true);
PS: although links redirect to Qt 5.xx documentation, solution works in both Qt 4.8 and Qt 5.xx.

Related

QTabWidget strange behavior

I have two tabs where placed QTableWidget with cell widget. See image.
QTabWidget *tab = new QTabWidget(this);
for (int i = 0; i < 2; ++i) {
QTableWidget *t = new QTableWidget(1, 1);
QPushButton *btn = new QPushButton("Click on me!");
t->setCellWidget(0, 0, btn);
connect(btn, &QPushButton::clicked, [=]() {
btn->hide();
});
tab->addTab(t, QString::number(i + 1));
}
setCentralWidget(tab);
The behavior you indicate is predictable, you must first know that if a widget becomes visible your children will also be visible.
Let's analyze the case of QTabWidget, this widget is essentially a QTabBar + QStackedWidget, the QStackedWidget manages the visibility of the widgets, and the latter internally has a QStackedLayout that when it establishes that a certain widget is wanted to show then it hides the current widget and shows the new one current widget. So every time you select tabbar the widget that is displayed will call the show method of that widget (in your case QTableWidget), and it will make your children visible even if they are hidden.
So if you want that if you have the need that works as you suppose a workaround should happen it is to save the status of the visibility in a property and in the showEvent method to apply the change if necessary.

QTableWidget selection rectangle does not disappear even after editing is finished

I am implementing a QTableWidget, the selection rectangle seems not to be disappearing even after I finish editing and change my selection to other cells.
Below is a screenshot of the QTableWidget.
Below is the code for constructing the tablewidget, rows are added dynamically via a QPushButton:
{
setObjectName(obj_name);
layout = new QVBoxLayout();
table = new QTableWidget(this);
table->verticalHeader()->setVisible(false);
table->verticalHeader()->setDefaultSectionSize(20);
table->setFixedWidth(180);
table->setColumnCount(3);
table->setColumnWidth(0,75);
table->setColumnWidth(1, 75);
table->setColumnWidth(2, 25);
QStringList header = { "Tag", "Threshold" ,""};
table->setHorizontalHeaderLabels(header);
table->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
add = new QPushButton("+", this);
add->setObjectName("btn_threshold_add");
layout->addWidget(table);
layout->addWidget(add);
setLayout(layout);
connect(add, SIGNAL(clicked()), this, SLOT(add_row()));
}
Below is the code for add_row() SLOT, triggers when user clicked the add button:
void TagThresholdWidget::add_row()
{
int row = table->rowCount();
QPushButton *del = new QPushButton("-", table);
table->insertRow(row);
table->setCellWidget(row, 2, del);
connect(del, SIGNAL(clicked()), this, SLOT(remove_row()));
}
Anyone has any clue to how to solve this problem? Its seems like a Qt graphical paint bug to me

QListWidget with custom widgets - not triggering itemClicked signal

I have listwidgetitem's that have a custom widget (step_widget) which contains 3 QPushButtons and a QLabel.
When I press one of the buttons in the widget, it is not triggering itemClicked which i need to see the index of the listwidget that was clicked. If i click the QLabel, the signal is triggered and i am able to obtain the index. How can trigger the signal when one of the buttons is pressed? Why does it not trigger?
QListWidgetItem *item = new QListWidgetItem();
stepWidget *step_widget = new stepWidget();
ui->listWidget->addItem(item);
ui->listWidget->setItemWidget(item,step_widget);
The itemClicked() signal is not emmited because the QPushButton consumes the click event.
There is the simplest solution I've found.
First, in your class stepWidget add a signal that will be emitted when any QPushButton is clicked, for example:
signals:
void widgetClicked();
Then connect the clicked() signal of every QPushButton with that signal. This code is in the constructor of the widget stepWidget:
connect(ui->pushButton1, &QPushButton::clicked, this, &stepWidget::widgetClicked);
connect(ui->pushButton2, &QPushButton::clicked, this, &stepWidget::widgetClicked);
connect(ui->pushButton3, &QPushButton::clicked, this, &stepWidget::widgetClicked);
To test it I added 10 widgets to a QListWidget that reside in the MainWindow class. You must connect that signal to a slot (in this case I use a C++11 Lambda Function, but you can create a slot instead, it's fine) where you establish the current item as the item under the widget. This code is located in the constructor of MainWindow:
for (int i = 0; i < 10; ++i) {
QListWidgetItem *item = new QListWidgetItem;
stepWidget *step_Widget = new stepWidget;
ui->listWidget->addItem(item);
ui->listWidget->setItemWidget(item, step_Widget);
connect(step_Widget, &stepWidget::widgetClicked, [=]() {
ui->listWidget->setCurrentItem(item);
});
}
Now, this will not make the itemClicked() signal to be emitted because the user not clicked the item. But I advice you to connect instead the signal currentRowChanged() as it will be emitted with this code and also it has the advantage that it allows you to directly obtain the row. Once you have the row you can obtain the item and the widget, evidently.
However, this procedure has the inconvenient that the currentRowChanged() signal will be emitted even when the user selects a row with the keyboard or when the user press and slide the mouse over the QListWidget without releasing it.
On workaround could be, for example, using a flag as an attribute for your MainWindow class that is always false except during this connection:
connect(ste_pWidget, &stepWidget ::widgetClicked, [=]() {
buttonPressed = true;
ui->listWidget->setCurrentItem(item);
buttonPressed = false;
});
Then you must manipulate two signals from the QListWidget: clicked() and currentRowChanged(). I choose clicked() instead of itemClicked() because it gives almost directly access to the row:
void MainWindow::on_listWidget_clicked(const QModelIndex &index)
{
ui->statusBar->showMessage(tr("Row clicked: %1").arg(index.row()), 1000);
}
void MainWindow::on_listWidget_currentRowChanged(int currentRow)
{
if (buttonPressed) {
ui->statusBar->showMessage(tr("Row clicked: %1").arg(currentRow), 1000);
}
}
what you can simply do is, make your qpushbutton to qlabel and then qpushbutton will become clickable.
You can then override this method :- on_listWidget_itemClicked(QListWidgetItem *item) for double click on qpushbutton.
I tried it & it worked perfectly, its quite simple workaround.

Qt - connect menuBar and QWidget

So I have menu bar like this:
this->layout = new QGridLayout;
QMenuBar* menuBar = new QMenuBar();
QMenu *fileMenu = new QMenu("File");
menuBar->addMenu(fileMenu);
fileMenu->addAction("Exit");
this->layout->setMenuBar(menuBar);
And I am wonderig how to connect thie action "Exit" with some slot my QWidget, I tryed something like this:
connect(menuBar,SIGNAL(menuBar->actions),this,SLOT(exitGame()));
But it is not working, can you tell me what I am doing wrong? And yes I have read manual about QMenuBar bud there are no examples of connecting. I have read about some connecting in Qt Designer but I am not using it.
You need to connect the QAction pointer returned from QMenuBar::addAction to the slot...
auto *exit_action = fileMenu->addAction("Exit");
connect(exit_action, &QAction::triggered,
[this](bool checked)
{
exitGame();
});

Adding multiple QDockWidget's

I am able to add QDockWidgets as follows:
QDW1 QDW2;
QDW3 QDW4;
by using the code
QDockWidget *dwidget = new QDockWidget(tr("QDW1"), this);
addDockWidget(Qt::LeftDockWidgetArea, dwidget);
dwidget = new QDockWidget(tr("QDW2"), this);
dwidget->show();
addDockWidget(Qt::LeftDockWidgetArea, dwidget);
QDockWidget *dwidget2 = new QDockWidget(tr("QDW2"), this);
addDockWidget(Qt::RighttDockWidgetArea, dwidget2);
dwidget2 = new QDockWidget(tr("QDW4"), this);
dwidget2->show();
addDockWidget(Qt::RighttDockWidgetArea, dwidget2);
Now I want to add as follows:
I want to add total of 6 QDockWidgets
QDW1 QDW2 QDW3;
QDW4 QDW5 QDW6;
Can you please give me an idea how to add the dock widgets in this 2X3 format?
Thank you for the help.
HBS
This should do the trick :
QDockWidget *dwidget = new QDockWidget(tr("QDW1"), this);
addDockWidget(Qt::RightDockWidgetArea, dwidget);
QDockWidget *dwidget2 = new QDockWidget(tr("QDW2"), this);
splitDockWidget(dwidget, dwidget2, Qt::Horizontal);
QDockWidget *dwidget3 = new QDockWidget(tr("QDW3"), this);
addDockWidget(Qt::RightDockWidgetArea, dwidget3);
QDockWidget *dwidget4 = new QDockWidget(tr("QDW4"), this);
splitDockWidget(dwidget3, dwidget4, Qt::Horizontal);
QDockWidget *dwidget5 = new QDockWidget(tr("QDW5"), this);
addDockWidget(Qt::RightDockWidgetArea, dwidget5);
QDockWidget *dwidget6 = new QDockWidget(tr("QDW6"), this);
splitDockWidget(dwidget5, dwidget6, Qt::Horizontal);
This is a pretty easy answer, maybe I am missing something - couldn't you just add three each to the top and bottom DockWidgetArea?
How does your main widget / layout look like? Usually dockWidgets are not intended as the sole content, no?