Why QGraphicsView is not shown - c++

I have the following codes in my Qt project with the following main:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
The class Widget is a QWidget object with the following constructor:
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_Scene = new QGraphicsScene(this);
QGraphicsLinearLayout* layout = new
QGraphicsLinearLayout(Qt::Orientation::Vertical);
for(int i = 0; i < 10; i++)
{
std::string name = "m_" + std::to_string(i);
GraphicsTextItem* item = new GraphicsTextItem(nullptr, QString(name.c_str()));
layout->addItem(item);
}
QGraphicsWidget* list = new QGraphicsWidget;
list->setPos(0,0);
list->setLayout(layout);
m_Scene->addItem(list);
QGraphicsView* view = new QGraphicsView(this);
view->setScene(m_Scene);
// Why one of these lines must be uncommented?
//m_Scene->setSceneRect(0, 0, 1920, 768);
//QVBoxLayout *ttopLayout = new QVBoxLayout;
//ttopLayout->addWidget(view);
//setLayout(ttopLayout);
}
GraphicsTextItem is just a QGraphicsWidget for displaying text:
class GraphicsTextItem : public QGraphicsWidget
{
public:
QString m_Name;
QColor m_Color;
public:
GraphicsTextItem(QGraphicsItem * parent = nullptr, const QString& name = QString());
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
{
Q_UNUSED(option)
Q_UNUSED(widget)
QFont font("Times", 10);
painter->setFont(font);
painter->setPen(m_Color);
painter->drawText(0, 0, m_Name);
}
};
My question is that why my scene is not shown. I must either define a SceneRect or define a layout on my widget?

I made an even shorter MCVE for demonstration:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QWidget qWinMain;
qWinMain.resize(320, 240);
QFrame qFrm(&qWinMain);
qFrm.setFrameStyle(QFrame::Box | QFrame::Raised);
qFrm.setLineWidth(0);
qFrm.setMidLineWidth(1);
qWinMain.show();
return app.exec();
}
compiled and started in cygwin64. This is how it looks:
There is a main window (with window manager decoration).
There is a child QFrame.
The child QFrame is "pressed" into the upper left corner.
How comes?
What QWidget does ensure: Child widgets are rendered (in front) when QWidget is rendered.
What QWidget is not (directly) responsible for: Layouting child widgets.
For this, a layout manager has to be plugged in:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QWidget qWinMain;
qWinMain.resize(320, 240);
QVBoxLayout qVBox(&qWinMain);
QFrame qFrm(&qWinMain);
qFrm.setFrameStyle(QFrame::Box | QFrame::Raised);
qFrm.setLineWidth(0);
qFrm.setMidLineWidth(1);
qVBox.addWidget(&qFrm);
qWinMain.show();
return app.exec();
}
compiled and started again in cygwin64. This is how it looks:
Now, the QFrame qFrm is filling the QWidget qWinMain nicely. Resize events received in qWinMain will be forwarded to the layout manager qVBox which will re-layout the children of qWinMain (i.e. qFrm) again.
I strongly believe OP's GraphicsView is just not visible because it has no minimal size requirement. (It's just to small to be visible.)
Hence, adding a layout manager ensures that the GraphicsView fills the parent widget client area. Resizing the contents of GraphicsView (by m_Scene->setSceneRect(0, 0, 1920, 768);) is yet another option to fix this, albeit the worse one.
Finally, the link to Qt Doc.: Layout Management.
Layout Management
The Qt layout system provides a simple and powerful way of automatically arranging child widgets within a widget to ensure that they make good use of the available space.
Introduction
Qt includes a set of layout management classes that are used to describe how widgets are laid out in an application's user interface. These layouts automatically position and resize widgets when the amount of space available for them changes, ensuring that they are consistently arranged and that the user interface as a whole remains usable.
All QWidget subclasses can use layouts to manage their children. The QWidget::setLayout() function applies a layout to a widget. When a layout is set on a widget in this way, it takes charge of the following tasks:
Positioning of child widgets
Sensible default sizes for windows
Sensible minimum sizes for windows
Resize handling
Automatic updates when contents change:
Font size, text or other contents of child widgets
Hiding or showing a child widget
Removal of child widgets

Related

Maximize QMdiSubWindow in QSplitter

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).

adding a custom widget in Layout at execution

I'm under Ubuntu 18.04 and using last QtCreator with last Qt5 framework
I'm trying to setup a vertical layout with at top an horizontal nested layout and under a custom made widget (based on clock exemple for the moment)
I setup a fresh widget project but as I dont understand yet how to get acess to nested layout from c++ code I removed automaticaly created mainform and created layout at execution.
If I use my custom widget as window it works if I use a window and add my custom widget it works but if I add a layout, add my custom widget to this layout and call setLayout on window it disappear...
I tried almost all orders : set the layout first or after adding my widget.
I tried to call show() on my widget or not befor or after adding it to layout
I tried to add the nested layer first or last nothing change
I 've read several time exemples and manual about layout and nested one
I can see my nested layout but not my widget
here's my main :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.setWindowTitle("WOUND : Windings Organiser with Usefull and Neat Drawings");
QVBoxLayout* hl=new QVBoxLayout;// top vertical layout
QHBoxLayout* slotqueryLayout=new QHBoxLayout; // nested first horizontal layout
QLabel *slotqueryLabel = new QLabel("Slot number:");
QLineEdit *slotqueryEdit = new QLineEdit("48");
slotqueryLayout->addWidget(slotqueryLabel);
slotqueryLayout->addWidget(slotqueryEdit);
hl->addLayout(slotqueryLayout);
WindingViewer* wv=new WindingViewer(&w); // my widget is just a simple canvas to draw things
hl->addWidget(wv);
wv->show(); // dont know if it's needed but if I remove it it dont change anything / tried to do it before or after adding to layout
w.setLayout(hl); // if called before adding content it dont change
w.show();
return a.exec();
}
and here you can find my custom widget:
class WindingViewer : public QWidget
{
Q_OBJECT
public:
explicit WindingViewer(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
signals:
public :
int SlotNumber;
public slots:
};
and
WindingViewer::WindingViewer(QWidget *parent) : QWidget(parent)
{
SlotNumber=3;
resize(200, 200);
}
void WindingViewer::paintEvent(QPaintEvent *)
{
int side = qMin(width(), height());
QColor SlotColor(127, 127, 127);
QPainter painter(this);
static const QPoint slotpolygonext[4] = {
QPoint(-2,85),
QPoint(-3,95),
QPoint(3, 95),
QPoint(2, 85)
};
static const QPoint slotpolygonint[5] = {
QPoint(-1,75),
QPoint(-2,85),
QPoint(2, 85),
QPoint(1, 75),
QPoint(-1,75),
};
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(width() / 2, height() / 2);
painter.scale(side / 200.0, side / 200.0);
painter.setPen(SlotColor);
for (int i = 0; i < SlotNumber; ++i) {
painter.drawPolyline(slotpolygonext,4);
painter.drawPolyline(slotpolygonint,5);
painter.rotate(360.0/SlotNumber);
}
}
I hope the question is clear enough. I've search for an answer here and over internet before posting. I found few things but nothing totaly related.
The custom widget is part of the window, you could see if manually with the mouse you make the height increase.
And then why is it hidden?
The layouts handle size policies and use the sizeHint() function of the widgets to obtain the default size, and in your case the sizeHint() is not implemented because it is not observed when the window is displayed, the solution is to implement that method:
*.h
public:
explicit WindingViewer(QWidget *parent = nullptr);
QSize sizeHint() const override;
*.cpp
QSize WindingViewer::sizeHint() const
{
return QSize(200, 200);
}

Qt Data Visualization: How to integrate a Q3DScatter graph into a Widget in a Main Window?

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?

Create a window in qt with shape from an image

Can some one explain me how to make a window in qt according to the shape of some object in an image , for example i have an image of a tree , using that i need to create a window in the shape of a tree ..
After a long search , myself found a good solution , check out this ..
#include <QtGui>
class myMainWindow:public QMainWindow
{
public:
myMainWindow():QMainWindow()
{
setMask((new QPixmap("saturn.png"))->mask());
QPalette* palette = new QPalette();
palette->setBrush(QPalette::Background,QBrush(QPixmap("saturn.png")));
setPalette(*palette);
setWindowFlags(Qt::FramelessWindowHint);
QWidget *centralWidget = new QWidget(this);
QGridLayout *layout = new QGridLayout();
centralWidget->setLayout(layout);
QPushButton* button1 = new QPushButton("Button 1");
button1->setFixedSize(80,50);
layout->addWidget(button1,0,0);
setCentralWidget(centralWidget);
};
~myMainWindow(){};
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
myMainWindow *window = new myMainWindow();
window->resize(600, 316);
window->show();
return app.exec();
}
Here is a recipe for making a widget with a semi-transparent background colour. Just expand from there by making the background fully transparent, then display the tree image on top of that as a background image. Note that the widget will still behave like a rectangular widget in regards to laying out its child elements, so you probably need to deal with this using some custom layout inside the tree shape.
Start from the docs for QWidget::setMask. It has a version which takes a QBitmap and one that takes a QRegion. This is the fundamental function in getting a transparent widget. The toolkit also includes a clock example using the QRegion version -- I suspect a bitmap is just as easy though.

Adding a label to a widget

I am trying to add a label to the main window using Qt. Here is a piece of the code:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget Main_Window;
QPixmap Image;
Image.load("1837.jpg");
QLabel i_label;
i_label.setPixmap(Image);
i_label.show();
QPushButton Bu_Quit("Quit", &Main_Window);
QObject::connect(&Bu_Quit, SIGNAL(clicked()), qApp, SLOT(quit()));
Main_Window.show();
return app.exec();
}
I've been having a very hard time figuring out how to properly add QLabels to QWidgets, I tried to set the Main_Window as the main widget using this method: app.setMainWidget(Main_Window) and the label was still outside the window. So how do I put labels into widgets using Qt?
hamza, this code worked fine for me:
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget Main_Window;
QLabel i_label("Start", &Main_Window);
//i_label.setPixmap(QPixmap("1837.jpg"));
QPushButton Bu_Quit("Quit" , &Main_Window);
QObject::connect(&Bu_Quit , SIGNAL(clicked()), qApp , SLOT(quit()));
QVBoxLayout *vbl = new QVBoxLayout(&Main_Window);
vbl->addWidget(&i_label);
vbl->addWidget(&Bu_Quit);
Main_Window.show();
return app.exec();
}
I commented setting the image code to show you that the label was set correctly. Make sure your image is valid (otherwise you won't see the text). The trick here was that you need to use qt layouts like QVBoxLayout
Add the label to a layout widget and set the window layout to that layout.
Design note: its better to create your own MainWindow class, inheriting from QMainWindow for instance, and design it from the inside.
or even better, use QtCreator.
You can try:
QWidget window;
QImage image("yourImage.png");
QImage newImage = image.scaled(150, 150, Qt::KeepAspectRatio);
QLabel label("label", &window);
label.setGeometry(100, 100, 100, 100);
label.setPixmap(QPixmap::fromImage(newImage));
window.show();
this way you can even decide where to put the label and choose the image size.