Is it possible to use QGraphicsLayout in an application with a QMainWindow? - c++

What I was hoping to do was have a standard QMainWindow class with menus, toolbar, plus various widgets in a layout, one of which would be a graphics view showing a graphics widget that contained a graphics layout. But whenever I put the graphics view into a main window nothing gets displayed. If I create my graphics view with the graphics widget containing a layout inside the main() function, then everything is visible.
As a test I took the working code provided in the Qt Basic Graphics Layouts Example, created a QMainWindow class in main, and moved the QGraphicsScene, Window and QGraphicsView creation to the main window class.
I tested the main window class on its own, and widgets like a line edit show up fine. But the code below, taken from main in the example, no longer works when in the main window class.
QGraphicsScene scene;
Window *window = new Window;
scene.addItem(window);
QGraphicsView view(&scene);
view.resize(600, 600);
view.show();
I just get a blank area. If I don't add the Window widget, but instead, for example, draw an ellipse then that is visible. If I add a plain QGraphicsWidget with a background colour then that is also visible. It is just when things are inside a layout on a graphics widget that I get nothing. I've been searching for answers, digging into the documentation and even looking through the Qt source to see if I can figure out if what I am trying to do is even possible, but without any luck.
My main window:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QGraphicsScene scene;
Window *window = new Window;
window->resize(600, 600);
scene.addItem(window);
QGraphicsView view(&scene);
view.resize(600, 600);
view.show();
setCentralWidget(&view);
resize(600,600);
}
Code in main:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}

One problem is here:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
[...]
QGraphicsView view(&scene);
view.resize(600, 600);
view.show();
[...]
}
You've declared the view widget on the stack, which means it will be automatically destroyed as soon as your MainWindow constructor returns, and thus the user will never see it. What you should do instead is something like this:
QGraphicsView * view = new QGraphicsView(&scene, this);
view->resize(600, 600);
view->show();
You'll have a similar problem with your QGraphicsScene object:
QGraphicsScene scene;
... since it is also declared as a local variable inside the constructor-method, it will also be destroyed when the constructor-method returns, leaving you with no scene. I suggest making it a class-member variable instead; that way it will last as long as your MainWindow does.
(Note that declaring items on the stack worked in the example-program you copied from, only because they were declared in the directly in the main() method, and main() doesn't return until the program is ready to exit... thus the objects in the example program would not be destroyed until the program was exiting anyway)

Related

Qt - Non Modal Dialog before Main Window is created

I've been struggling to do this : I want to show on a window a QWidget, or a QDialog before the MainWindow is created, but I cannot use exec() because it will enter its loop and won't create my MainWindow before I accept or reject the dialog.
The reason I want to do this is to have a widget showing information while the MainWindow constructs itself. I don't want to keep this extra window once the MainWindow is showing up.
I believe the issue comes from the fact that the main window is already created when a.exec() is called and the window won't show up before a.exec(). The solution I found is to use a QDialog instead and call exec() but it blocks the rest of the code which I don't want to happen.
Code :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartUpDialog start; //this is my custom QDialog, can be a QWidget if necessary.
qDebug() << "starting up!";
MainWindow w;
start.exec(); //I tried show() but it won't show up.
w.startApp(&start); //this function will do some stuff.
w.show();
//I don't want start to stay after mainwindow shows up
return a.exec();
}
Here is what I tried so far :
I tried to create and show the StartUpDialog while constructing the MainWindow but it won't work out.
Use start.show(), but it won't show before the mainwindow does, both for a QWidget and a QDialog.
Use start.exec(), this does what I want but it's modal and I couldn't make it non-modal with SetModal(false) or setWindowModality(Qt:NonModal).
I also tried to use start.exec() and attempted to reimplement accepted() and exec() so that it automatically calls accepted() as soon as it appears but it will still close the window.
Hopefully you can help me in that issue, and thanks for reading !
UPDATE : Solved thanks to Trap, here is how I made it :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartUpDialog start;
QSplashScreen *splash = new QSplashScreen();
StartUpWidget *start = new StartUpWidget(splash);
splash->resize(350,380);
start->show();
splash->raise();
splash->show();
qDebug() << "starting up!";
MainWindow w;
w.startApp(start);
w.show();
splash->finish(&w);
start->deleteLater();
splash->deleteLater();
return a.exec();
}
My only concern is that I use a Gif inside my widget using QMovie and updating it has to be done manually apparently.
If I understand your problem correctly (showing a dialog until your main window is created), you should have a look at the QSplashScreen class : http://doc.qt.io/qt-5/qsplashscreen.html

How to correct my code to see small size widget on my top left of my screen?

I started to learn C++ and Qt with a beginner's book. After reading some of them(about 10%), I wrote a code that just create my first simple widget on my laptop screen. In my theory using setGeometry(0, 0, 50, 50), I could see the small size widget on top left of my screen. But when I run the code, big size widget come out from middle of my screen. What is heppening. How to correct my code to see small size widget on my top left of my screen?
Here is my c++ code:
#include <QApplication>
#include <QWidget>
class MyWidget : public QWidget{
QWidget w;
public:
MyWidget();
};
MyWidget::MyWidget(){
w.setGeometry(0, 0, 50, 50);
};
int main(int argc, char *argv[]){
QApplication app(argc, argv);
MyWidget mw;
mw.show();
return app.exec();
}
You create a new QWidget w; inside your MyWidget class which you shouldn't need. Remove that and change your constructor code to:
MyWidget::MyWidget(){
setGeometry(0, 0, 50, 50); // calls function on *this*
};
In your original code setGeometry was not being applied to the correct MyWidget object, but rather the instance w of your MyWidget which is not shown.

Qt creating MDI document window

I am trying to create a MDI document program. I have a question on creating the subwindow.
This is my mainwindow constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle(tr("MDI"));
workspace = new QMdiArea;
setCentralWidget(workspace);
//fileNew();
createActions();
createMenus();
createToolbars();
statusBar()->showMessage(tr("Done"));
enableActions();
}
The interesting point is the fileNew(); function. It is a private slot function actually which I want to invoke when "New File" button is triggered. Here is the private slot fileNew() function:
void MainWindow::fileNew()
{
DocumentWindows* document = new DocumentWindows;
workspace->addSubWindow(document);
}
This function works perfectly when I call from the mainwindow constructor. However, there is a problem when I call it from the createActions(); function which uses a signal-slot mechanism.
Here is my createActions()
void MainWindow::createActions()
{
newAction = new QAction(QIcon(":/Image/NewFile.png"),tr("&New"),this);
newAction->setShortcut(tr("Ctrl+N"));
newAction->setToolTip(tr("Open new document"));
connect(newAction, SIGNAL(triggered(bool)), this, SLOT(fileNew()));
}
No subwindow is created even the SLOT is triggered. Subsequently, I find out that if I add document->show();, everything works well.
void MainWindow::fileNew()
{
DocumentWindows* document = new DocumentWindows;
workspace->addSubWindow(document);
document->show();
}
My question is: Why the show() function is needed in a SLOT but not in the constructor?
PS. DocumentWindows is just a class inherits QTextEdit.
This problem has nothing to do with the class of the widgets one is using. It is unrelated to documents, MDI, or the main window. After you add a child widget to a widget that is already visible, you must explicitly show it. Otherwise, the widget will remain hidden.
All widgets are hidden by default. When you initially show the MainWindow, all of its children are recursively shown too. When you later add a child MDI widget, it remains hidden. When widgets are added to layouts, they are shown by default - but your widget is managed by the MDI area, not by a layout.
This is a minimal test case demonstrating your issue:
// https://github.com/KubaO/stackoverflown/tree/master/questions/widget-show-32534931
#include <QtWidgets>
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QWidget w;
w.setMinimumSize(200, 50);
QLabel visible{"Visible", &w};
w.show();
QLabel invisible{"Invisible", &w};
invisible.move(100, 0);
return app.exec();
}

Custom QWidget Not Showing in QMainWindow (Qt4.8)

Summary: I wish to use X11 to paint a custom QWidget. It works unless that widget is in a layout or QMainWindow
I have a custom widget derived from QWidget that I'd like to be the main widget in a QMainWindow. When I run something like this:
int main(int argc, char** argv) {
QApplication app(argc, argv);
ModelWidget mw;
mw.show();
return app.exec();
}
everything works fine, including resizing, obscuring and revealing the window contents, etc.
However, if I try to use that widget as the central widget in a QMainWindow, nothing is painted in the central widget area of the QMainWindow.
Here's the constructor of the QMainWindow:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
modelwidg = new ModelWidget;
setCentralWidget(modelwidg);
createActions();
createMenus();
}
I get the feeling that there's something related to the size or resize policy of my custom widget that I need to implement, but I can't find any documentation regarding what functions must be provided by a widget for it to be usable as a central widget in a QMainWindow. What am I missing?
Edit: Here's the custom widget
ModelWidget::ModelWidget(QWidget *parent) :
QWidget(parent)
{
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_NativeWindow);
setAutoFillBackground(true);
const QX11Info &info = x11Info();
// Elided X11 and glX specific stuff
create(wnd, true, true);
}
void ModelWidget::paintEvent(QPaintEvent *)
{
// scene.render is just some OpenGL stuff
scene->render();
glXSwapBuffers(dpy, glxwnd);
}
void ModelWidget::resizeEvent(QResizeEvent * e)
{
glViewport(0, 0, e->size().width(), e->size().height());
scene->set_aspect(float(e->size().width()) / float(e->size().height()));
update();
}
QSize ModelWidget::sizeHint() const
{
return QSize(640, 480);
}
Further...
According to the docs,
To render outside of Qt's paint system, e.g., if you require native
painting primitives, you need to reimplement QWidget::paintEngine() to
return 0 and set [Qt::WA_PaintOnScreen].
I've done that, but the window still remains unpainted. I suspect that one of my X11 objects, Window, Display*, is being altered by adding this widget to a layout or MainWindow.

Must construct a QApplication before a QWidget

Everywhere only just "before QPaintDevice" questions and nowhere is my error. So, here we go.
I need an extern QWidget to be able to get access to it from outside (because I don't know any other ways to do it). Basically, I need this: Create 2 QWidgets from 1 window, go to first window and from there hide main window and show second window created by main window (although main window is not main(), it is QWidget too).
I added
extern QWidget *widget = new QWidget
everywhere and everyhow in possible ways, and I still got this message. I suppose, it means that I need to create my QApplication (in main.cpp) and only then declare any QWidgets. But then HOW can I access those QWidgets from another QWidgets?
Code is here:
https://github.com/ewancoder/game/tree/QWidget_before_QApp_problem
P.S. The final goal is to be able show and hide both gamewindow.cpp and world.cpp from battle.cpp (just regular class)
And btw, adding Q_OBJECT and #include both don't work.
Anyway, if I cannot use functions from one window to another, than what's the point? I can have one window in another, and then another in that one, and then one in that another... but I can't do anything from the last to the previous. After years on Delphi that seems strange to me.
Don't use extern or otherwise static variables which lead to creation of the widget before the QApplication is created in main. The QApplication must exist before the constructor of the QWidget is executed.
Instead of sharing the variable via extern, either make the other windows members of the main window, and then make the windows known to each other by passing around pointers, or keep them private in MainWindow and request the actions from the subwindows e.g. via signal/slots. As a generic rule, don't use global variables but class members.
In the following FirstWindow (which is supposed hide main window and secondWindow) gets the main window and the second window passed via pointers and then just calls show/hide on them directly.
int main(int argc, char **argv) {
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
In main window, have two members for the two other windows, say FirstWindow and SecondWindow:
class MainWindow : public QMainWindow {
...
private:
FirstWindow *m_firstWindow;
SecondWindow *m_secondWindow;
};
MainWindow::MainWindow(QWidget *parent) {
m_firstWindow = new FirstWindow; //not pass this as parent as you want to hide the main window while the others are visible)
m_secondWindow = new SecondWindow;
m_firstWindow->setMainWindow(this);
m_firstWindow->setSecond(m_secondWindow);
m_firstWindow->show(); //Show first window immediately, leave second window hidden
}
MainWindow::~MainWindow() {
//Manual deletion is necessary as no parent is passed. Alternatively, use QScopedPointer
delete m_firstWindow;
delete m_secondWindow;
}
FirstWindow, inline for brevity:
class FirstWindow : public QWidget {
Q_OBJECT
public:
explicit FirstWindow(QWidget *parent = 0) : QWidget(parent) {}
void setMainWindow(MainWindow *mainWindow) { m_mainWindow = mainWindow); }
void setSecondWindow(SecondWindow *secondWindow) { m_secondWindow = secondWindow; }
private Q_SLOTS:
void somethingHappened() { //e.g. some button was clicked
m_mainWindow->hide();
m_secondWindow->show();
}
private:
MainWindow* m_mainWindow;
SecondWindow* m_secondWindow;
};
Maybe not helping the former author, but others facing the problem.
I simply got this error by mistaking a debug-library with a release one. So check your linker settings, if you are sure the implementation is done right (first instancing application and then using widgets).