Program in gtkmm will not show buttons - c++

I am trying to write a program in gtkmm but the buttons will not show up. I've done everything I know to make these buttons show, but nothing has been working. I have even included the 'show all' methods in both the main and win_home.cpp files but still nothing happens. The program DOES however go through the code, as the cout statements are all being printed. Does anyone have any idea why these buttons would not be showing up?
main.cpp:
#include <gtkmm.h>
#include <iostream>
#include "win_home.h"
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "com.InIT.InITPortal");
std::cout << "Creating Portal Window" << std::endl;
HomeGUI win_home;
win_home.set_default_size(600,400);
win_home.set_title("St. George InIT Home");
return app->run(win_home);
}
win_home.cpp:
#include "win_home.h"
HomeGUI::HomeGUI()
{
//build interface/gui
this->buildInterface();
//show_all_children();
//register Handlers
//this->registerHandlers();
}
HomeGUI::~HomeGUI()
{
}
void HomeGUI::buildInterface()
{
std::cout << "Building Portal Interface" << std::endl;
m_portal_rowbox = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 5);
add(m_portal_rowbox);
Gtk::Button m_pia_button = Gtk::Button("Printer Install Assistant");
m_portal_rowbox.pack_start(m_pia_button, false, false, 0);
m_pia_button.show();
Gtk::Button m_inventory_button = Gtk::Button("Inventory");
m_inventory_button.show();
m_portal_rowbox.pack_start(m_inventory_button, false, false, 0);
m_inventory_button.show();
//add(m_portal_rowbox);
//m_portal_rowbox.show_all();
m_portal_rowbox.show();
this->show_all_children();
std::cout << "Completed Portal Interface" << std::endl;
return;
}
void HomeGUI::registerHandlers()
{
}

In void HomeGUI::buildInterface() you have constructed 2 buttons and they are added it to your box container. When the function returns the buttons are destroyed as they are now out of scope. Since they no longer exist they can not be visible.
So for you first button you would use something like this:
Gtk::Button * m_pia_button = Gtk::manage(
new Gtk::Button("Printer Install Assistant"));
m_portal_rowbox.pack_start(&m_pia_button, false, false, 0);
m_pia_button.show();
I expect you would need easy access to your buttons throughout the life time of your window. The easiest way is to have the buttons as a member of your class. It will be constructed as an empty button and you just need to set the label afterwards.
class HomeGUI {
....
// A button (empty)
Gtk::Button m_pia_button;
....
};
....
void HomeGUI::buildInterface()
{
....
m_pia_button.set_label("Printer Install Assistant");
m_portal_rowbox.pack_start(m_pia_button, false, false, 0);
m_pia_button.show();
....
}

Related

How to make GtkScrolledWindow work together with GtkFixed inside GtkOverlay

The basic problem is this:
I have a bunch of widgets that the user can move around. This is achieved by using a GtkOverlay as the outer container, and inside this, is a bunch of GtkFixed, each containing the corresponding widget:
GtkOverlay
GtkFixed
Widget A
GtkFixed
Widget B
...
The reason for the outer GtkOverlay is that GtkFixed lacks support for z-index. Now each GtkFixed covers the entire area. Thus, to make it possible to activate a widget that is currently below, the pass-through property has to be set on each child of the GtkOverlay. The system works for the leaf widgets GtkScale and GtkDrawingArea. However, If I put something inside a GtkScrolledWindow in GTK assumes that the GtkScrolledWindow is located in the upper left corner of the GtkFixed, which in general is wrong. Unsetting the pass-through property solves the problem, but then other widgets become inaccessible. Is there any workaround for this.
I think the proper solution would be to have each child of the GtkOverlay not to occupy the whole area. Then pass-through would not be needed, but I think it is not possible to do this with GTK (or maybe you could if you write your own layout container, which behaves like a web page with free floating layers.
Minimal non-working example:
//# {
//# "targets":[{"name":"minimal-nonworking-example-so-64090741","type":"application", "pkgconfig_libs":["gtk+-3.0"]}]
//# }
#include <gtk/gtk.h>
#include <string>
#include <vector>
#include <algorithm>
// To be able to feed the list box
template<class Callback>
void readlines(FILE* src, Callback&& cb)
{
std::string buffer;
while(true)
{
auto ch_in = getc(src);
if(ch_in == -1)
{
if(buffer.size() != 0)
{
cb(buffer);
}
return;
}
if(ch_in=='\n')
{
cb(buffer);
buffer.clear();
}
else
{
buffer+=ch_in;
}
}
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
auto mainwin = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
gtk_window_set_title(mainwin, "ListBoxTest");
gtk_window_set_default_size(mainwin, 800, 500);
auto overlay = GTK_OVERLAY(gtk_overlay_new());
gtk_container_add(GTK_CONTAINER(mainwin), GTK_WIDGET(overlay));
gtk_widget_set_size_request(GTK_WIDGET(overlay), 500, 300);
auto frame = GTK_FRAME(gtk_frame_new(nullptr));
auto fixed = GTK_FIXED(gtk_fixed_new());
gtk_fixed_put(fixed, GTK_WIDGET(frame), 60, 60);
gtk_overlay_add_overlay(overlay, GTK_WIDGET(fixed));
// {
// Without this line, GtkScrolledWindow works as expected, but if there were more layers
// other layers would become inaccessible
gtk_overlay_set_overlay_pass_through(overlay, GTK_WIDGET(fixed), TRUE);
// }
gtk_overlay_reorder_overlay(overlay, GTK_WIDGET(fixed), -1);
auto scrolled_window = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(nullptr, nullptr));
gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(scrolled_window));
gtk_widget_set_size_request(GTK_WIDGET(frame), 128, 128);
auto listbox = GTK_LIST_BOX(gtk_list_box_new());
gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(listbox));
gtk_widget_show_all(GTK_WIDGET(mainwin));
readlines(stdin, [listbox](auto&& item) {
auto label = GTK_LABEL(gtk_label_new(item.c_str()));
gtk_label_set_justify(label, GTK_JUSTIFY_LEFT);
gtk_widget_set_halign(GTK_WIDGET(label), GTK_ALIGN_START);
gtk_list_box_insert(listbox, GTK_WIDGET(label), -1);
});
gtk_widget_show_all(GTK_WIDGET(fixed));
gtk_main();
gtk_widget_destroy(GTK_WIDGET(mainwin));
return 0;
}

How to get the QLineEdit text offset when have QAction at leading position

I have a QLineEdit with a QAction at leading position. I want to know the start position of the text but I don't find how to do:
QLineEdit *le = new QLineEdit(parent);
le->addAction(QIcon(":/myicon"), QLineEdit::LeadingPosition);
// Now I want to get the text start position
// but both return "QMargins(0, 0, 0, 0) QMargins(0, 0, 0, 0)"
qDebug() << le->textMargins() << le->contentsMargins();
I searched in the qt's github sources to find if the addAction() method does something on the contents or text margins but without success.
I must admit that (before reading OPs question) I was not aware about QLineEdit::addAction(). Thus, I wrote a little sample testQLineEditAction.cc:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// init GUI
QLineEdit qEdit;
qEdit.addAction(QIcon("./document-properties.svg"), QLineEdit::LeadingPosition);
qEdit.addAction(QIcon("./document-save.svg"), QLineEdit::TrailingPosition);
qEdit.show();
// runtime loop
return app.exec();
}
and this is how it looks (compiled in cygwin64):
Afterwards, I digged a bit through woboq.org to find out how it is implemented.
I started in QLineEdit::paintEvent():
void QLineEdit::paintEvent(QPaintEvent *)
{
...
QStyleOptionFrame panel;
initStyleOption(&panel);
...
QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
r.setX(r.x() + d->effectiveLeftTextMargin());
r.setY(r.y() + d->topTextMargin);
r.setRight(r.right() - d->effectiveRightTextMargin());
r.setBottom(r.bottom() - d->bottomTextMargin);
This is interesting: The rectangle for contents is retrieved and then corrected by inner offsets.
QFontMetrics fm = fontMetrics();
...
QRect lineRect(r.x() + d->horizontalMargin, d->vscroll, r.width() - 2*d->horizontalMargin, fm.height());
About the d->horizontalMargin, I'm not quite sure but I ignored it for now and followed instead d->effectiveLeftTextMargin():
int QLineEditPrivate::effectiveLeftTextMargin() const
{
return effectiveTextMargin(leftTextMargin, leftSideWidgetList(), sideWidgetParameters());
}
...
static int effectiveTextMargin(int defaultMargin, const QLineEditPrivate::SideWidgetEntryList &widgets,
const QLineEditPrivate::SideWidgetParameters &parameters)
{
if (widgets.empty())
return defaultMargin;
return defaultMargin + (parameters.margin + parameters.widgetWidth) *
int(std::count_if(widgets.begin(), widgets.end(),
[](const QLineEditPrivate::SideWidgetEntry &e) {
return e.widget->isVisibleTo(e.widget->parentWidget()); }));
}
So, I came to the conclusion that QLineEditPrivate::effectiveLeftTextMargin() considers the space for action icons when effective size of text rectangle is determined.
It's a pity that all these functions are private and thus not accessable from outside. After thinking a while how to get access to these from outside and looking into doc. whether I haven't overseen something, I got the idea to use the QActions directly for this:
#include <QtWidgets>
void inspect(const QString &cmd, QAction &qCmd)
{
qDebug() << (cmd + "->associatedWidgets().size():")
<< qCmd.associatedWidgets().size();
int i = 0;
for (QWidget *const pQWidget : qCmd.associatedWidgets()) {
qDebug() << '[' << i++ << "]:"
<< typeid(*pQWidget).name()
<< "geometry:" << pQWidget->geometry();
}
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// init GUI
QLineEdit qEdit;
qEdit.setText("012345678901234567890123456789");
QAction *const pQCmd1
= qEdit.addAction(QIcon("./document-properties.svg"), QLineEdit::LeadingPosition);
QAction *const pQCmd2
= qEdit.addAction(QIcon("./document-save.svg"), QLineEdit::TrailingPosition);
qEdit.show();
qDebug() << "qEdit.geometry():" << qEdit.geometry();
inspect("pQCmd1", *pQCmd1);
inspect("pQCmd2", *pQCmd2);
// runtime loop
return app.exec();
}
Console output:
Qt Version: 5.9.4
qEdit.geometry(): QRect(0,0 200x23)
"pQCmd1->associatedWidgets().size():" 2
[ 0 ]: 9QLineEdit geometry: QRect(0,0 200x23)
[ 1 ]: 19QLineEditIconButton geometry: QRect(4,2 22x18)
"pQCmd2->associatedWidgets().size():" 2
[ 0 ]: 9QLineEdit geometry: QRect(0,0 200x23)
[ 1 ]: 19QLineEditIconButton geometry: QRect(174,2 22x18)
To compare the values, another snapshot with modified icons (frame drawn in SVGs to show icon size) which has been magnified (factor 5):
Left QLineEditIconButton reported position (4, 2) but the left frame of icon is 8 pixels away from left border of QLineEdit. There is surely a frame around the QLineEditIconButton which has to be considered as well (and I didn't investigate how to retrieve it). The width of frame might be subject of style engine and thus vary between platforms. To make such attempt robust and portable, the respective values should be retrieved from the widgets or from style. This starts to become a tedious fiddling with more or less chance for success.
I ended up once in a similar situation when trying to answer SO: How to automatically increase/decrease text size in label in Qt.
Concerning QLineEdit::cursorRect():
I believe that using QLineEdit::cursorRect() is (as well) at best fragile.
I modified my above example to check this out:
#include <QtWidgets>
class LineEdit: public QLineEdit {
public:
QRect cursorRect() const { return QLineEdit::cursorRect(); }
};
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// init GUI
LineEdit qEdit;
qEdit.setText("012345678901234567890123456789");
qEdit.addAction(QIcon("./document-properties.svg"), QLineEdit::LeadingPosition);
qEdit.addAction(QIcon("./document-save.svg"), QLineEdit::TrailingPosition);
qEdit.show();
qDebug() << "qEdit.cursorRect():" << qEdit.cursorRect();
// runtime loop
return app.exec();
}
Console output:
Qt Version: 5.9.4
qEdit.geometry(): QRect(0,0 200x23)
qEdit.cursorRect(): QRect(253,0 9x16)
Funny, that the cursor x-position is not only quite high – it's even higher than the width of qEdit. How comes? The initial text "012345678901234567890123456789" I put into qEdit causes the cursor to be close to the right whereby horizontal scrolling happens. The cursor position seems to be related to the virtual text width (including the clipped range on the left side).
After having to deal with this problem myself recently, I found a very simple solution:
QLineEdit.setTextMargins(24, 0, 0, 0)
Where the parameters refer to left, top, right, and bottom text margins.
I am using PyQt5, but the idea is the same for Qt as well.

Handling different gui states

So I want to create the gui interface in Qt/cpp for the server which can be in many different states, and depending on its state the buttons in gui need to be set differently ex:
GUI:
button1 - unchecked and enabled to click
button2 - disabled(grayed out)
button3 - disabled
button3 - disabled
Then after click button1
GUI:
button1 - checked
button2 - enabled to click
button3 - enabled to click
button3 - enabled to click
But for example if server is in different state and you connect via gui the buttons should look like this:
GUI:
button1 - checked
button2 - enabled to click
button3 - disabled to click
button3 - disabled to click
Is there some established pattern/way of handling that intuitively? The biggest problem here is that if the server has a lot of different states that need the buttons to be set in a lot of different configurations. The only thing I can come up with is mapping the state of all buttons to the specific state but well... there's a lot of buttons and a lot of states.
You could try using flags, the idea is that when an event happens and you want the GUI to change you set a flag which in turn is recalled in a loop. Below you can see the general idea and concept.
If you change the state of the flag you will get a different output and it will loop over and over listening for events just write the GUI code for each in the different states.
#include <iostream>
using namespace std;
int getserverstatusfunction() {/*your code to check server status returns 0,1 or 2*/
return 0;
}
UI.button.click(true) { getresult = 1; }; //change the UI state when the button is clicked
int main() {
bool running;
while (running){
int getresult = getserverstatusfunction();
if (getresult == 0)
{
cout << "Draw flag one interface code\n";
}
else if (getresult == 1)
{
cout << "Draw flag two interface code\n";
}
else {
cout << "Draw flag three interface code\n";
}
system("pause");
return 0;
}
I've found the best way to do this is just to have a single slot-method (e.g. UpdateAllButtonStates() that updates all of your buttons and checkboxes, e.g.:
void MyWindow::UpdateAllButtonStates() // Qt-slot method
{
const bool shouldButton1BeEnabled = [...];
button1->setEnabled(shouldButton1BeEnabled);
const bool shouldButton2BeEnabled = [...];
button2->setEnabled(shouldButton2BeEnabled);
[... and so on for all enables and checked/unchecked states in your GUI]
}
... then anytime your program's internal state has changed in any way that might require an update to one or more buttons/checkboxes in the GUI, call this method explicitly, or set up a signal/slot connection that will call it for you.
The advantage of doing it this way is the simplicity -- with this approach, it's trivial to guarantee that your GUI widgets will be in updated to the expected state after any internal-state-change, because there is only one code-path to write and debug. The alternative (trying to come up with the correct transitional behavior for every possible state-change in your program) quickly leads to an intractable amount of complexity, and endless debugging and hair-pulling.
You might think the downside is inefficiency -- after all, we are updating all the buttons even though in any cases, only one of them may have changed -- but Qt's code is smart enough that calling setEnabled(false) on a button that is already disabled is a no-op (likewise calling setEnabled(true) on a button that is already enabled, and so on), so the heavyweight code of redrawing a widget's pixels will only be executed when the widget's state has actually changed.
The logic inside UpdateAllButtonStates() that calculates shouldButton1BeEnabled, etc, does get executed a lot, but it usually ends up being pretty trivial logic so that turns out not to be important. However, if for some reason that logic turns out to be expensive, you have the option of reducing the frequency at which UpdateAllButtonStates() gets executed, by using asynchronous execution and a boolean "dirty-bit", e.g.:
void MyWindow::ScheduleUpdateAllButtonStates() // Qt-slot method
{
if (_dirtyBit == false)
{
_dirtyBit = true;
QTimer::singleShot(0, this, SLOT(UpdateAllButtonStates()));
}
}
void MyWindow::UpdateAllButtonStates()
{
if (_dirtyBit == false) return;
_dirtyBit = false;
// Update button enables/checked states as previously, here
}
... then have all your internal-state-change code call ScheduleUpdateAllButtonStates() rather than calling UpdateAllButtonStates() directly; the advantage is that even if ScheduleUpdateAllButtonStates() gets called 500 times in a row, it will only result in UpdateAllButtonStates() getting called once, during the next iteration of Qt's event loop.
Enabling/disabling button UI logic can be very dirty and difficult to manage and trace. Also, sometimes we want to be in particular state and want to make a minor change like changing state of just one button. Here is an approach. It's generic but you will have to adrop it accordingly with your UI.
#include <iostream>
class UIState
{
protected:
bool btn1;
bool btn2;
bool btn3;
public:
UIState()
{
btn1 = false;
btn2 = false;
btn3 = false;
}
virtual void setBtn1State(bool new_state)
{
btn1 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
virtual void setBtn2State(bool new_state)
{
btn2 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
virtual void setBtn3State(bool new_state)
{
btn3 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
};
class UIStateAllEnabled : public UIState
{
public:
UIStateAllEnabled()
{
btn1 = true;
btn2 = true;
btn3 = true;
std::cout << btn1 << btn2 << btn3 << std::endl;
}
};
class UIStateAllDisabled : public UIState
{
public:
UIStateAllDisabled()
{
btn1 = false;
btn2 = false;
btn3 = false;
std::cout << btn1 << btn2 << btn3 << std::endl;
}
};
class UI
{
UIState * currentState;
public:
UI()
{
currentState = NULL;
}
~UI()
{
if (currentState != NULL)
{
delete currentState;
std::cout << "deleted current state" << std::endl;
}
}
void setState(UIState * new_state)
{
// should also check for if already current state?
UIState * prevState = currentState;
currentState = new_state;
if (prevState != NULL)
{
delete prevState;
std::cout << "deleted previous state" << std::endl;
}
}
void setBtn1State(bool new_state)
{
currentState->setBtn1State(new_state);
};
void setBtn2State(bool new_state)
{
currentState->setBtn2State(new_state);
};
void setBtn3State(bool new_state)
{
currentState->setBtn3State(new_state);
};
};
int main()
{
UI ui;
// enable all buttons
ui.setState(new UIStateAllEnabled);
// Now say you want to change state of a particular button within this state.
ui.setBtn1State(false);
ui.setBtn3State(false);
// switch to a completely new state, disable all buttons
ui.setState(new UIStateAllDisabled);
// customize within that sate
ui.setBtn3State(true);
return 0;
}

unhandled exception widget with sdkTrays in Ogre

I have some serious issues with sdkTrays in Ogre.
I have my OgreKinectGame that inherits from BaseApplication. BaseApplication is creating logo etc. using sdkTrayManager. I thought this mTrayMgr was inherited and can be used in my application as well.
I am trying to setup widgets for a HUD, but I'm getting unhandled exception errors.
My setupWidgets() function looks like this.
void OgreKinectGame::setupWidgets()
{
if(!mTrayMgr)
mTrayMgr = new SdkTrayManager("InterfaceName", mWindow, mMouse);
//mTrayMgr->destroyAllWidgets(); this caused exceptions as well
// create check boxes to toggle the visibility of our particle systems
const int WIDTH_UI = 160;
// main menu
mTrayMgr->createLabel(TL_CENTER, "mMainMenuLabel", "Main Menu", WIDTH_UI);
mTrayMgr->createButton(TL_CENTER, "mOptionButton", "Option");
mTrayMgr->createButton(TL_CENTER, "mCreditButton", "About");
mTrayMgr->createButton(TL_CENTER, "mQuitButton", "Quit");
mTrayMgr->showAll();
}
First, where did you initialize your setupWidgets()? , on BaseApplication class, they have setup(), you can create a virtual of this setup() to your main class and then initialize your setupWiget() there, e.g.,
bool OgreKinectGame::setup(void)
{
if (!BaseApplication::setup()) {
return false;
}
// Load fonts for tray captions
FontManager::getSingleton().getByName("SdkTrays/Caption")->load();
setupWidgets();//initialize here for your setupWidget()
}
second, I think your setupWidget() should be like this,
void OgreKinectGame::setupWidgets()
{
const int WIDTH_UI = 160;
// main menu
mTrayMgr->createLabel(TL_CENTER, "mMainMenuLabel", "Main Menu", WIDTH_UI);
mTrayMgr->createButton(TL_CENTER, "mOptionButton", "Option");
mTrayMgr->createButton(TL_CENTER, "mCreditButton", "About");
mTrayMgr->createButton(TL_CENTER, "mQuitButton", "Quit");
}
Can you try this solution and back again if still get crash?

Yes/No message box using QMessageBox

How do I show a message box with Yes/No buttons in Qt, and how do I check which of them was pressed?
I.e. a message box that looks like this:
You would use QMessageBox::question for that.
Example in a hypothetical widget's slot:
#include <QApplication>
#include <QMessageBox>
#include <QDebug>
// ...
void MyWidget::someSlot() {
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "Test", "Quit?",
QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes) {
qDebug() << "Yes was clicked";
QApplication::quit();
} else {
qDebug() << "Yes was *not* clicked";
}
}
Should work on Qt 4 and 5, requires QT += widgets on Qt 5, and CONFIG += console on Win32 to see qDebug() output.
See the StandardButton enum to get a list of buttons you can use; the function returns the button that was clicked. You can set a default button with an extra argument (Qt "chooses a suitable default automatically" if you don't or specify QMessageBox::NoButton).
You can use the QMessage object to create a Message Box then add buttons :
QMessageBox msgBox;
msgBox.setWindowTitle("title");
msgBox.setText("Question");
msgBox.setStandardButtons(QMessageBox::Yes);
msgBox.addButton(QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
if(msgBox.exec() == QMessageBox::Yes){
// do something
}else {
// do something else
}
QT can be as simple as that of Windows. The equivalent code is
if (QMessageBox::Yes == QMessageBox(QMessageBox::Information, "title", "Question", QMessageBox::Yes|QMessageBox::No).exec())
{
}
I'm missing the translation call tr in the answers.
One of the simplest solutions, which allows for later internationalization:
if (QMessageBox::Yes == QMessageBox::question(this,
tr("title"),
tr("Message/Question")))
{
// do stuff
}
It is generally a good Qt habit to put code-level Strings within a tr("Your String") call.
(QMessagebox as above works within any QWidget method)
EDIT:
you can use QMesssageBox outside a QWidget context, see #TobySpeight's answer.
If you're even outside a QObject context, replace tr with qApp->translate("context", "String") - you'll need to #include <QApplication>
QMessageBox includes static methods to quickly ask such questions:
#include <QApplication>
#include <QMessageBox>
int main(int argc, char **argv)
{
QApplication app{argc, argv};
while (QMessageBox::question(nullptr,
qApp->translate("my_app", "Test"),
qApp->translate("my_app", "Are you sure you want to quit?"),
QMessageBox::Yes|QMessageBox::No)
!= QMessageBox::Yes)
// ask again
;
}
If your needs are more complex than provided for by the static methods, you should construct a new QMessageBox object, and call its exec() method to show it in its own event loop and obtain the pressed button identifier. For example, we might want to make "No" be the default answer:
#include <QApplication>
#include <QMessageBox>
int main(int argc, char **argv)
{
QApplication app{argc, argv};
auto question = new QMessageBox(QMessageBox::Question,
qApp->translate("my_app", "Test"),
qApp->translate("my_app", "Are you sure you want to quit?"),
QMessageBox::Yes|QMessageBox::No,
nullptr);
question->setDefaultButton(QMessageBox::No);
while (question->exec() != QMessageBox::Yes)
// ask again
;
}
If you need asynchronous call you should use open and result methods instead of question or exec. Sample code inside a QWidget method:
QMessageBox* const message = new QMessageBox(QMessageBox::Icon::Question, tr("Test"),
tr("Quit?"), QMessageBox::Button::Yes | QMessageBox::Button::No, this);
message->setDefaultButton(QMessageBox::Button::No);
message->open();
connect(message, &QDialog::finished, this, [message] {
message->deleteLater();
if (message->result() == QMessageBox::Button::Yes) {
QApplication::quit();
}
});
It should not be usefull just for a quit dialog but for other confirmation dialogs where parent widget might be destroyed by external events it is the main way to avoid a crash.
Python equivalent code for a QMessageBox which consist of a question in it and Yes and No button. When Yes Button is clicked it will pop up another message box saying yes is clicked and same for No button also. You can push your own code after if block.
button_reply = QMessageBox.question(self,"Test", "Are you sure want to quit??", QMessageBox.Yes,QMessageBox.No,)
if button_reply == QMessageBox.Yes:
QMessageBox.information(self, "Test", "Yes Button Was Clicked")
else :
QMessageBox.information(self, "Test", "No Button Was Clicked")
If you want to make it in python you need check this code in your workbench.
also write like this.
we created a popup box with python.
msgBox = QMessageBox()
msgBox.setText("The document has been modified.")
msgBox.setInformativeText("Do you want to save your changes?")
msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
msgBox.setDefaultButton(QMessageBox.Save)
ret = msgBox.exec_()