I have a weird scenario. I create a QMainWindow that is embedded in a QGraphicsScene. I want to have multiple QMainWindows each with a toolbar inside the scene. I'm simulating an MDI Area, without using the QMdiArea class.
Here is the MainWindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
resize(1000, 750);
qApp->setStyle(QStyleFactory::create("Fusion"));
QGraphicsView* view = new QGraphicsView;
QGraphicsScene* scene = new QGraphicsScene;
view->setFixedSize(1000, 750);
view->setScene(scene);
view->scene()->setSceneRect(-150, -150, view->size().width(), view->size().height());
setCentralWidget(view);
QWidget* widget = new QWidget;
widget->resize(300, 300);
QVBoxLayout* vLay = new QVBoxLayout;
widget->setLayout(vLay);
QMainWindow* testWindow = new QMainWindow;
testWindow->resize(300, 300);
QToolBar* toolbar = new QToolBar;
toolbar->setFloatable(false);
toolbar->setStyleSheet("border: 1px solid red"); //For better seeing the issue
toolbar->addAction("Test");
testWindow->addToolBar(toolbar);
vLay->addWidget(testWindow);
scene->addWidget(widget);
}
What happens is the QToolBar will spawn in the correct location on the embedded QMainWindow, but when it's moved and docked anywhere, it will snap too far up and too far to the left. I've added outliner code to outline the toolbar so you can see the toolbar box.
Here is the MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QToolBar>
#include <QVBoxLayout>
class MainWindow : public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
};
#endif // MAINWINDOW_H
Why does the toolbar do this weird snapping effect? I added the QMainWindow into a QWidget on purpose, as it's needed for something I'm doing. I realize that embedding just the QMainWindow has the desired interaction, but I need it embedded in the QWidget. I also realize that not having parents are bad for memory management, but I handle that as well.
I'm on Qt Version 5.10.1 and I'm using Redhat as my OS.
Related
I am writing Qt/C++ project and I created my mainwindow.ui in QtDesigner. I placed in mainwindow.ui an empty widget which later I want to extend by putting there my widget written in code. This is my code:
class which extends QWidget
#pragma once
#include <QtGui>
#include <QWidget>
using namespace QtDataVisualization;
class GraphDataCreator : public QWidget
{
Q_OBJECT
public:
GraphDataCreator(QWidget* parent = 0);
~GraphDataCreator();
};
cpp of this class:
#include "GraphDataCreator.h"
GraphDataCreator::GraphDataCreator(QWidget* parent)
: QWidget(parent)
{
this->setStyleSheet("background-color:green;");
}
and the mainwindow class:
#pragma once
#include <QMainWindow>
#include "ui_MainWindow.h"
#include "GraphDataCreator.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QMainWindow*parent = Q_NULLPTR);
~MainWindow();
private:
Ui::MainWindow ui;
};
cpp of main window class
#include "MainWindow.h"
#include <string>
#include <QtGui>
#include "GraphDataCreator.h"
MainWindow::MainWindow(QMainWindow*parent)
: QMainWindow(parent)
{
ui.setupUi(this);
QGridLayout* layout = new QGridLayout(ui.Chart3DWidget);
GraphDataCreator* chart3D = new GraphDataCreator(ui.Chart3DWidget);
layout->addWidget(chart3D);
QWidget* test_widget = new QWidget;
test_widget->setStyleSheet("background-color: red;");
layout->addWidget(test_widget);
ui.Chart3DWidget->setLayout(layout);
}
I wanted to be the whole widget in ui green, but it didn't appear so I put there test_widget with red background and the result is that it is half nothing/half red. So the green widget excists there but it is not visible. And my question is why the green part is not visible??? And how to solve it?
Of course names of classes are weird because I tried to do something else and this explanation simplifies that problem.
EDIT:
thx #sajas for help! Actually I used that link Why do stylesheets not work when subclassing QWidget and using Q_OBJECT? and I used case 2 written there so I deleted Q_OBJECT macro in GraphDataCreator class and it worked without any other changes. The function for background color of widget I left the same and everything else. The result is as expected half green / half red. Anyway I think I should include macro Q_Object as written in link over there because it is a Qt class, but it does work without. Maybe there is a small bug in Qt??? To sum up if you delete Q_Object macro it works.
I need to create a new window over top of my current program (I'm attempting a dialog in this case) when a button is clicked. I have this working, but I am having trouble editing the content of the Dialog. As far as I'm aware, no .ui file is created for this and it is only being created when I connect the button to the function.
I have tried using a QMessageBox but was unable to resize the window how I needed. And still ran into the issue of adding the other elements.
void MyNameSpace::openInfoDialog()
{
QDialog* Dialog = new QDialog(this);
Dialog->setWindowTitle("View Stuff");
Dialog->setMinimumSize(500,250);
Dialog->adjustSize();
DialogRunner* msgRunner = new DialogRunner(Dialog, this);
msgRunner->safeExec();
}
This is my connect
connect(_Widget.InfoBtn, SIGNAL(clicked(bool)), this, SLOT(openInfoDialog()));
This code does produce a dialog on click, but I need to be able to add things like labels etc to it. I also use QT Designer as my WYSIWYG.
What can I do to create the new window from a button click and have it filled with other text etc ?
I have this working, but I am having trouble editing the content of
the Dialog
You can add ui files in your project:
Using that option Qt Creator will make a class with cpp and h files and a ui file in which you can add other widgets as you're used to.
use the import directives to use your class where you need it like you did in the code above and you will have your ui file available.
Then connect the clicked signal of your button with the slot of your dialog class. You can do that in the constructor of the class that holds the button.
You can read this approach more in detail in the book C++ GUI Programming
with Qt 4
on chapter 2 : Creating Dialogs.
It is available for free on the web. It uses Qt4, but in Qt5 it works the same way around.
EDIT: Here is a minimal example that shows you where you can use the needed parts: a mainwindow with a button on it (in the ui file). a Dialog class which also has a ui file (with several widgets on it). When clicking the button on the mainwindow, the dialog form is shown. Thjs is what I asked you for before. It makes it easier to communicate / test.
pro file
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = test
TEMPLATE = app
SOURCES += \
dialog1.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
dialog1.h \
mainwindow.h
FORMS += \
dialog1.ui \
mainwindow.ui
**main.cpp**
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
**mainwindow.cpp**
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialog1.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
Dialog1* dialog = new Dialog1(this);
connect( ui->pushButton_1, SIGNAL(clicked()), dialog, SLOT(show()));
}
MainWindow::~MainWindow()
{
delete ui;
}
dialog1.h
namespace Ui {
class Dialog1;
}
class Dialog1 : public QDialog
{
Q_OBJECT
public:
explicit Dialog1(QWidget *parent = nullptr);
~Dialog1();
private:
Ui::Dialog1 *ui;
};
#endif // DIALOG1_H
dialog1.cpp
#include "dialog1.h"
#include "ui_dialog1.h"
Dialog1::Dialog1(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog1)
{
ui->setupUi(this);
}
Dialog1::~Dialog1()
{
delete ui;
}
I'm trying to group a few QPushButton`s into QButtonGroup with exclusive checking, but after launch i'm still able to check multiple buttons.
// pen toggle button
penB.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
penB.setIconSize(QSize(ICON_SIZE,ICON_SIZE));
penB.setCheckable(true);
penB.toggle();
penB.setIcon(QIcon(":icons/pen.png"));
// circle toggle button
circleB.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
circleB.setIconSize(QSize(ICON_SIZE,ICON_SIZE));
circleB.setCheckable(true);
circleB.setIcon(QIcon(":icons/circle.png"));
figureBox.addButton(&penB);
figureBox.addButton(&circleB);
figureBox.setExclusive(true);
// add buttons to grid
layoutG.addWidget(&openB,1,1);
layoutG.addWidget(&saveB,1,2);
layoutG.addWidget(&penB,1,3);
layoutG.addWidget(&circleB,2,3);
I think, its just need to procees some events. If its true, which events exactly?
Thanks in advance.
I've tried to replicate your example and for me it works OK:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include <QButtonGroup>
#include <QGridLayout>
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
QGridLayout layoutG;
QButtonGroup figureBox;
QPushButton openB;
QPushButton saveB;
QPushButton penB;
QPushButton circleB;
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent)
{
// pen toggle button
penB.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
penB.setIconSize(QSize(16, 16));
penB.setCheckable(true);
penB.toggle();
// circle toggle button
circleB.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
circleB.setIconSize(QSize(16, 16));
circleB.setCheckable(true);
figureBox.addButton(&penB);
figureBox.addButton(&circleB);
figureBox.setExclusive(true);
// add buttons to grid
layoutG.addWidget(&openB,1,1);
layoutG.addWidget(&saveB,1,2);
layoutG.addWidget(&penB,1,3);
layoutG.addWidget(&circleB,2,3);
setLayout(&layoutG);
}
Widget::~Widget()
{
}
The single thing that could be not ok in your code is that I don't see where you set the layout, but maybe you didn't add the code for simplicity reasons. Another thing is that the only excluding buttons would be penB and circleB.
Check my example, see what you're doing wrong and maybe come back with a feedback.
Sorry, guys. Its time to go to the bed. Im forgot to declare QButtonGroup in .h file, it was declared at the local function, so just memory leak.
I'm a beginner in using Qt and I have a problem. I want to display red background using QGraphicsView and QGraphicsScene. Instead of red, I'm still displaying the white one. I don't know, where the problem exists.
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QBrush>
class Screen:public QGraphicsView
{
Q_OBJECT
public:
Screen();
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
Screen::Screen()
{
QGraphicsView *view = new QGraphicsView(this);
QGraphicsScene *scene = new QGraphicsScene();
QBrush redBrush(Qt::red);
scene->setBackgroundBrush(redBrush);
view->setScene(scene);
}
Main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Screen scr;
scr.show();
return a.exec();
}
The problem with the code you posted is there there are two different QGraphicsView objects being created -- one is the Screen object (scr), which is a subclass of QGraphicsView and therefore is a QGraphicsView object, and the other is the (view) object that you allocated with 'new' in the Screen constructor.
You're setting the scene attribute of the second one, but never showing it or doing anything with it. You're seeing the first one displayed on screen (since that is the one you call show() on inside main()), but since you never set its scene attribute, it remains blank/white.
The easiest fix is to get rid of the unnecessary second QGraphicsView object. I changed the Scene constructor to this:
Screen::Screen()
{
QGraphicsScene *scene = new QGraphicsScene();
scene->setBackgroundBrush(Qt::red);
setScene(scene);
}
... and having done that, the program now displays the red window that you would expect.
I will start off by explaining my main goal. I have a main window with 7 buttons on it(amongst other things), when you hit each button, it closes out the current window and opens up a new window. All the windows will have the same 7 buttons, so you can go between each window. With all windows having the exact same 7 buttons, I wanted to set up a function that each class can call to set up each button and connect to a slot() in my mainwindow.cpp(called setupSubsystemButtons in example below). However, I can't seem to get the window to close using the standard "this->close()"...it works when I go from the main window to another window(the main window closes) but when I go from a different window to say the home window, the different window doesn't close. Suggestions would be greatly appreciated. My guess is that my understanding of "this" when it comes to calling slots in another class is wrong.
mainwindow.cpp( the parts that are relevant)
void MainWindow::ECSgeneralScreen()
{
ECSgeneralCommand *ECSgeneral = new ECSgeneralCommand;
this->close();
ECSgeneral->show();
//opens up the ECS screen
}
void MainWindow::homeScreen()
{
MainWindow *home = new MainWindow;
this->close();
home->show();
//opens up the ECS screen
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setupSubsystemButtons(QGridLayout *layout)
{
//Push Button Layout
homeScreenButton = new QPushButton("Home");
layout->addWidget(homeScreenButton, 3, 11);
connect(homeScreenButton, SIGNAL(clicked()), this, SLOT(homeScreen()));
ECSgeneralScreenButton = new QPushButton("General");
layout->addWidget(ECSgeneralScreenButton,5,11);
connect(ECSgeneralScreenButton, SIGNAL(clicked()), this, SLOT(ECSgeneralScreen()));
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QDialog>
namespace Ui {
class MainWindow;
}
class MainWindow : public QDialog
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
QWidget *window;
void setupSubsystemButtons(QGridLayout *layout);
~MainWindow();
private slots:
public slots:
void ECSgeneralScreen();
void homeScreen();
};
#endif // MAINWINDOW_H
ecsgeneralcommandWindow
include "ecsgeneralcommand.h"
#include "mainwindow.h"
#include <QtWidgets>
#include <QtCore>
ECSgeneralCommand::ECSgeneralCommand(MainWindow *parent) : QDialog(parent)
{
QGridLayout *layout = new QGridLayout;
QWidget::setFixedHeight(600);
QWidget::setFixedWidth(650);
...
//Setup Subsystem Buttons
test.setupSubsystemButtons(layout);
setLayout(layout);
}
ecsgeneralcommandWindow header
#ifndef ECSGENERALCOMMAND_H
#define ECSGENERALCOMMAND_H
#include <QDialog>
#include <QMainWindow>
#include <QtWidgets>
#include <QObject>
#include "mainwindow.h"
class ECSgeneralCommand : public QDialog
{
Q_OBJECT
public:
explicit ECSgeneralCommand(MainWindow *parent = 0);
private:
MainWindow test;
public slots:
};
#endif // ECSGENERALCOMMAND_H
Slots are just normal functions. When Qt invokes a slot, it ends up calling the appropriate receiver's method. In other words, this equals to the value of the 3rd argument of your connect statements. You passed this there, so the receiver is MainWindow object. E.g. MainWindow::homeScreen method always tries to close MainWindow. If it is already hidden, this action takes no effect.
You should either have a slot in each window class and connect buttons to appropriate receivers, or use a pointer to the currently active window instead of this when calling close(). But your architecture is strange in the first place. Why would you need to create these buttons for each window? It is reasonable to create them once and use in all windows. Also hiding and showing windows is not necessary. You can create one main window with buttons and a QStackedWidget that will contain the content of all other windows. Maybe you can even use QTabWidget instead of these buttons.