Code below
#include <QtWidgets>
#include <QGLWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
w.setCentralWidget(new QGLWidget(&w)); // w.setCentralWidget(new QWidget(&w));
QTreeWidget* tree = new QTreeWidget(&w);
QTreeWidgetItem* item0 = new QTreeWidgetItem(tree, QStringList("a"));
QTreeWidgetItem* item1 = new QTreeWidgetItem(tree, QStringList("b"));
tree->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(tree, &QTreeView::customContextMenuRequested, [](){
QMenu menu;
menu.addAction("a");
menu.exec(QCursor::pos());
});
QDockWidget* dock = new QDockWidget("Tree", &w);
dock->setWidget(tree);
w.addDockWidget(Qt::LeftDockWidgetArea, dock);
w.show();
return a.exec();
}
Compile and run it. It requires 2 right clicks to switch context menus among items. However, if I change QGLWidget to QWidget. It is fine. 1 right click can switch context menus among items. Any bugs??? Thanks a lot.
Some observations:
Switch the positions of the tree and the GL widget is ok, i.e. set the tree as the central widget and GL Widget as the one in the dock.
It seems the right click event goes to the central widget and then is blocked by the GL widget.
Related
I have QSplitter set as the central widget:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
mdiArea(new QMdiArea)
{
QWidget *widget = new QWidget;
widget->setMinimumSize(100, 100);
QSplitter *splitter = new QSplitter;
splitter->addWidget(mdiArea);
splitter->addWidget(widget);
setCentralWidget(splitter);
createActions();
}
void MainWindow::createSubwin()
{
QWidget *subwin = new QWidget(mdiArea);
subwin->setWindowTitle("Subwindow");
subwin->setMinimumSize(100, 100);
mdiArea->addSubWindow(subwin);
subwin->show();
}
void MainWindow::createActions()
{
QAction *actSub = new QAction("Add subwindow", this);
connect(actSub, SIGNAL(triggered()), SLOT(createSubwin()));
QMenu *winMenu = menuBar()->addMenu("Windows");
winMenu->addAction(actSub);
}
When I press maximize button of subwindow, the subwindow covers entire main window. Is there any way to prevent such behaviour and make subwindow occupy all the space of QMdiArea instead?
UPD: It looks like that the problem occurs only when at least one menu in main window's QMenuBar is present. Without menuBar everything works as expected:
https://www.qtcentre.org/threads/44457-QMdiSubWindow-maximizing-problem
Regarding the QSplitter, I gave OP the following hint:
Move the right part of the QSplitter into a dock widget (and drop the QSplitter), so that the left part is the only part of the QMainWindow::centralWidget(). This would mean to work with the existing class instead of against, and is probably easier to manage.
OP appreciated the hint with the dock widget but claimed the sub-window will still occupy the whole main window.
I must admit my lack of experience with MDI and made an MCVE to prove me myself right or wrong:
#include <QtWidgets>
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QMainWindow qWinMain;
qWinMain.setWindowTitle("QMainWindow - MDI - Dock");
qWinMain.resize(640, 480);
// MDI
QMdiArea qMDI;
qWinMain.setCentralWidget(&qMDI);
// MDI sub widget
QLabel qWinSub("MDI Sub-Window\nwidget");
qMDI.addSubWindow(&qWinSub);
// Dock
QDockWidget qDock;
qDock.setWindowTitle("Dock");
QLabel qLblDock("Dock\nwidget");
qDock.setWidget(&qLblDock);
qWinMain.addDockWidget(Qt::RightDockWidgetArea, &qDock);
qWinMain.show();
// runtime loop
return app.exec();
}
Output:
So, I cannot reproduce OPs claim—it works on my side.
My platform: Windows 10, VS2019, Qt5.15
I enhanced the first MCVE a bit to see how it works if MDI sub-windows are created after qWinMain.show() (what's expected as the usual case).
#include <QtWidgets>
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QMainWindow qWinMain;
qWinMain.setWindowTitle("QMainWindow - MDI - Dock");
qWinMain.resize(640, 480);
// MDI
QMdiArea qMDI;
qWinMain.setCentralWidget(&qMDI);
// Dock
QDockWidget qWinDock;
qWinDock.setWindowTitle("Dock");
QWidget qDock;
QVBoxLayout qVBoxDock;
QPushButton qBtnNewMDISubWin("New Sub-Window");
qVBoxDock.addWidget(&qBtnNewMDISubWin);
qDock.setLayout(&qVBoxDock);
qWinDock.setWidget(&qDock);
qWinMain.addDockWidget(Qt::RightDockWidgetArea, &qWinDock);
// create sub-window
int i = 0;
auto createSubWin = [&]() {
++i;
QLabel* pQWinSub = new QLabel(QString("MDI Sub-Window\nwidget %1").arg(i));
pQWinSub->setWindowTitle(QString("MDI Sub-Window %1").arg(i));
qMDI.addSubWindow(pQWinSub);
pQWinSub->show();
};
// install signal handlers
QObject::connect(&qBtnNewMDISubWin, &QPushButton::clicked,
createSubWin);
// runtime loop
qWinMain.show();
return app.exec();
}
Output:
It still works on my side as expected.
Note:
I had to add the explicit pQWinSub->show(); after qMDI.addSubWindow(pQWinSub); (which was not necessary in the first MCVE). However, this is exactly how it's done by OP's code.
OPs reply:
It turns out that the problem occurs only when menuBar is present
Oha. How comes?
I extended my MCVE again to add a menu bar:
#include <QtWidgets>
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QMainWindow qWinMain;
qWinMain.setWindowTitle("QMainWindow - MDI - Dock");
qWinMain.resize(640, 480);
// menu
QMenuBar qMenuMain;
QAction qCmdFile("File");
QMenu qMenuFile;
QAction qCmdFileNew("New");
qMenuFile.addAction(&qCmdFileNew);
qCmdFile.setMenu(&qMenuFile);
qMenuMain.addAction(&qCmdFile);
qWinMain.setMenuBar(&qMenuMain);
// MDI
QMdiArea qMDI;
qWinMain.setCentralWidget(&qMDI);
// Dock
QDockWidget qWinDock;
qWinDock.setWindowTitle("Dock");
QWidget qDock;
QVBoxLayout qVBoxDock;
QPushButton qBtnNewMDISubWin("New Sub-Window");
qVBoxDock.addWidget(&qBtnNewMDISubWin);
qDock.setLayout(&qVBoxDock);
qWinDock.setWidget(&qDock);
qWinMain.addDockWidget(Qt::RightDockWidgetArea, &qWinDock);
// create sub-window
int i = 0;
auto createSubWin = [&]() {
++i;
QLabel* pQWinSub = new QLabel(QString("MDI Sub-Window\nwidget %1").arg(i));
pQWinSub->setWindowTitle(QString("MDI Sub-Window %1").arg(i));
pQWinSub->setFrameShape(QFrame::Box);
qMDI.addSubWindow(pQWinSub);
pQWinSub->show();
};
// install signal handlers
QObject::connect(&qCmdFileNew, &QAction::triggered,
createSubWin);
QObject::connect(&qBtnNewMDISubWin, &QPushButton::clicked,
createSubWin);
// runtime loop
qWinMain.show();
return app.exec();
}
Output:
Note:
I partly agree with OP:
Yes, the look of the maximized MDI is a bit different now. It looks like it occupies the whole client area of the main window but…
…the dock widget is still visible. I added a box to the QLabel (the top widget in the MDI sub-window) to illustrate this. In fact, the sub-window still occupies the central widget only (regardless what the look of its title bar suggests).
I would like to show the status of icons in toolbar (whether they are activated). For example, When I click Bold, Italic or Underline icon in Microsoft word, it will be shaded, and switch to normal status when I click it again.
It's not necessary to be shaded. I just need to distinguish whether it is activated.
You have to checkable the QAction, or use a QWidget that is checkable like QToolButton:
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QToolBar *toolbar = w.addToolBar("Toolbar");
QAction *bold_action = toolbar->addAction("B");
QFont bold_fn(bold_action->font());
bold_fn.setBold(true);
bold_action->setFont(bold_fn);
bold_action->setCheckable(true);
QAction *italic_action = toolbar->addAction("I");
QFont fn_cursive(italic_action->font());
fn_cursive.setItalic(true);
italic_action->setFont(fn_cursive);
italic_action->setCheckable(true);
QAction *underline_action = toolbar->addAction("U");
QFont fn_underline(underline_action->font());
fn_underline.setUnderline(true);
underline_action->setFont(fn_underline);
underline_action->setCheckable(true);
QAction* subscript_action = new QAction;
subscript_action->setIcon(QIcon(":/subscript.png"));
subscript_action->setCheckable(true); // <---
toolbar->addAction(subscript_action);
w.setCentralWidget(new QTextEdit);
w.resize(320, 240);
w.show();
return a.exec();
}
Output:
I'm trying to display a Q3DScatter graph in a Main Window designed with Qt Designer so I've added a widget to the main window but I don't know how to embed the graph object in this widget. I tried to create a widget "container" programmatically and embed the graph in it and then putting the widget in a QHBoxLayout (which has been added to the main window using Qt Designer) using the following code in my main window's constructor:
...
Q3DScatter *graph = new Q3DScatter();
QWidget *container = QWidget::createWindowContainer(graph);
ui->horizontal_layout->addWidget(container, 1);
But the window appears to be empty when executing. I'd really appreciate some help.
EDIT: Here's the full code of my main window constructor:
ResultsWindow::ResultsWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ResultsWindow)
{
ui->setupUi(this);
Q3DScatter *graph = new Q3DScatter();
QWidget *container = QWidget::createWindowContainer(graph);
ui->horizontal_layout->addWidget(container, 1);
}
And here's the main code:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ResultsWindow w;
w.show();
return a.exec();
}
EDIT 2: I forgot to specify that the horizontal layout is embedded in a GridLayout. I tried to create a new project and my code actually works perfectly when I add a horizontal layout directly to the main window. So could the problem be due to the GridLayout?
I want to create custom Layout alike here: http://doc.qt.io/qt-5/qtwidgets-layouts-flowlayout-flowlayout-cpp.html
I want some methood to put checkbox on top of custom button. For now there are
setGeometry(QRect(QPoint(...
methods for either button and checkbox but whether I'm doing it for button or checkobox first still checkbox appears "under" the button and I can't see/click it.
How can I put checkbox on top of button there?
Simply make the checkbox a child of the button and call setGeometry relative to the button. Children are always drawn on top of their parents.
QPushButton button("Hello World!", &w);
button.setGeometry(0,0,100,100);
button.show();
QCheckBox checkBox(&button);
checkBox.setGeometry(button.rect());
checkBox.show();
No need to put the checkbox into a layout.
I have just made this snippet to check the checkbox on the top of the button and it works for me.
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
#include <QCheckBox>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QPushButton button("Hello World!", &w);
button.setGeometry(0,0,100,100);
button.show();
QCheckBox checkBox(&w);
checkBox.setGeometry(30,30,50,50);
checkBox.show();
w.show();
return a.exec();
}
and here is if you will change the order of "parenting" and want checkbox still be on the top:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QCheckBox checkBox(&w);
checkBox.setGeometry(30,30,50,50);
checkBox.show();
QPushButton button("Hello World!", &w);
button.setGeometry(0,0,100,100);
button.show();
checkBox.setParent(NULL);
checkBox.setParent(&w);
w.show();
return a.exec();
}
What I want to do with this piece of code is set the focus on the QMenu Item programmatically. But neither QMenu::setActiveAction() nor QMenu::popup() works.
How can I do that?
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QMainWindow *window = new QMainWindow();
window->setWindowTitle(QString::fromUtf8("Test:QMenu"));
window->resize(336, 227);
QAction *newAct = new QAction("&New",window);
QAction *openAct = new QAction("&Open",window);
QAction *saveAct = new QAction("&Save",window);
QMenu *fileMenu;
fileMenu = window->menuBar()->addMenu("&File");
fileMenu->addAction(newAct);
fileMenu->addAction(openAct);
fileMenu->addAction(saveAct);
window->show();
fileMenu->popup(QPoint(10,10));
return app.exec();
}
QMenu items are not "focusable" in the same manner as other widgets. And, actually, they shouldn't, because what you want is not common practice of their usage.
As a workaround, on mouse press you can get mouse cursor position, pre-calculate offset of your default menu item in the popup menu and show the menu at the point, where mouse cursor underly your default menu item. This solution was suggested here.
Also, what will be more nice for user, to select default menu item you can generates narrow keys buttons events after you display your popup. This works on Windows, but not sure about other OS.