I am new to Qt 5.0 and I am trying to use a QGraphicsView called "missionView" of size 700x400 inside a QWidget to show a rectangle. However, nothing shows up inside the graphics view on running the application. Here is the constructor of the QWidget "MainView" where I am doing everything
MainView::MainView(QWidget *parent) :
QWidget(parent),
ui(new Ui::MainView)
{
ui->setupUi(this);
QGraphicsScene scene(0, 0, 500, 500);
QGraphicsRectItem* myrect = scene.addRect(QRectF(0,0,15,5),QPen(), QBrush());
ui->missionView->setScene(&scene);
ui->missionView->setVisible(true);
ui->missionView->show();
ui->missionView->update();
printf("QGraphicsScene scene's items: %d\n",scene.items().size());
for (int i = 0; i < scene.items().size(); i++) {
printf("%d\n",scene.items().at(i));
}
}
The last print statement does show that one item has been added but still nothing gets shown. I have tried an approach similar to this but this too dosent work. Can anyone please explain this.
You're creating the scene object on the stack.
Thus the scene will be destroyed right away at the end of the constructor and thus nothing will be shown.
Create the scene on the heap and/or make it a class member and it should work.
Related
I am trying to build an application that after getting some user input on the first window, pops up another window and displays some results. However, even though the menubar is visible on the first window, the menubar does not appear on the second window. The two windows are objects of different classes, but both classes are inherited from QMainWindow.
I have tried using the menuBar() function which returns a pointer for the menubar to add menus (this works for the first window). I also tried creating a new menubar object which didn't help either.
//MapWindow.h
class MapWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MapWindow(QWidget *parent = nullptr);
~MapWindow();
private:
QAction *vehicleAct;
QAction *missionAct;
QAction *backAct;
QMenu *toolMenu;
};
//MapWindow.cpp
MapWindow::MapWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MapWindow)
{
ui->setupUi(this);
setWindowState(Qt::WindowMaximized);
vehicleAct = new QAction("Vehicle Selection");
vehicleAct->setShortcut(Qt::CTRL + Qt::Key_V);
missionAct = new QAction("Mission Selection");
missionAct->setShortcut(Qt::CTRL + Qt::Key_M);
backAct = new QAction("Back");
backAct->setShortcut(Qt::CTRL + Qt::Key_B);
toolMenu = menuBar()->addMenu("Tools");
toolMenu->addAction(vehicleAct);
toolMenu->addAction(missionAct);
toolMenu->addAction(backAct);
}
MapWindow::~MapWindow() {
delete ui;
}
When I use the same code in the WelcomeWindow class which is also inherited from QMainWindow it works perfectly. However it doesn't even show a menubar in this second window.
I managed to find the problem. One of my widgets (QScrollArea) was located in the top left corner of the screen which was stopping the whole menubar from displaying for some reason. Moving the QScrollArea down a little bit has solved the problem.
A qDockWidget containing a qCustomPlot always starts with zero height. I am able to catch the qDockWidget resize event and change the qCustomPlot geometry using these answers, but the qCustomPlot is always hidden until it is manually stretched. Should this happen automatically, or do I need to calculate and set the dock height at startup?
This sample code creates a new qCustomPlot widget, places it in a layout, places that layout in another widget, and sets it to the dock. I have also tried placing the qCustomPlot widget directly into the dock. qCustomPlot setGeometry, setMinimumSize, and setSizePolicy seem to have no effect on the dock height.
#include <QMainWindow>
#include "qcustomplot.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(){
QCustomPlot *m_customPlot;
QDockWidget *dock;
resize(1200, 600);
//create the plot
QWidget *plot_frame_temp= new QWidget();
plot_frame_temp->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding);
m_customPlot = new QCustomPlot(plot_frame_temp);
m_customPlot->axisRect()->setupFullAxesBox(true);
m_customPlot->setBackground(Qt::black);
//size and margin settings
m_customPlot->setGeometry(QRect(0, 0, 500, 400));
m_customPlot->axisRect()->setMinimumSize(500,400);
m_customPlot->axisRect()->setAutoMargins(QCP::msLeft|QCP::msBottom|QCP::msRight|QCP::msTop);
// zoom and drag only on horrizontal axis
m_customPlot->axisRect()->setRangeZoomAxes(m_customPlot->xAxis,nullptr);
m_customPlot->axisRect()->setRangeDragAxes(m_customPlot->xAxis,nullptr);
//setup the top axis and labels
m_customPlot->xAxis->setVisible(false);
m_customPlot->xAxis2->setVisible(true);
m_customPlot->xAxis2->setTicks(true);
m_customPlot->xAxis2->setTickLabels(true);
m_customPlot->xAxis2->setTickPen(QColor(136, 136, 136));
m_customPlot->xAxis2->setTickLength(0,10);
m_customPlot->xAxis2->setTickLabelColor(QColor(136, 136, 136));
m_customPlot->xAxis2->setSubTickPen(Qt::NoPen);
m_customPlot->xAxis2->setBasePen(Qt::NoPen);
QFont font;
font.setStyleStrategy(QFont::PreferOutline);
m_customPlot->xAxis2->setTickLabelFont(font);
//setup the left axis and hide
m_customPlot->yAxis->setVisible(false);
m_customPlot->yAxis->setRangeReversed(true);
m_customPlot->yAxis2->setVisible(false);
//first graph
m_customPlot->addGraph();
m_customPlot->graph()->setPen(QPen(QColor(165, 165, 165)));
m_customPlot->graph()->setLineStyle((QCPGraph::lsStepLeft));
//second graph
m_customPlot->addGraph();
m_customPlot->graph()->setPen(QPen(QColor(165, 165, 165)));
m_customPlot->graph()->setLineStyle((QCPGraph::lsStepLeft));
// make some data
QVector<double> x(500), y0(500), y1(500);
for (int i=0; i<500; ++i)
{
x[i] = i;
y0[i] = (rand() % 2 + 0.2)/2;
y1[i] = (rand() % 2 + 1.4)/2;
}
//add data to graph
m_customPlot->graph(0)->setData(x, y0);
m_customPlot->graph(1)->setData(x, y1);
// set some options
m_customPlot->setNotAntialiasedElements(QCP::aeAll);
m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
//add plot widget to layout
QHBoxLayout *laLayout = new QHBoxLayout();
laLayout->addWidget(plot_frame_temp);
//add layout to another widget
QWidget *laWidget=new QWidget();
laWidget->setLayout(laLayout);
//add second widget to dock
dock = new QDockWidget(tr("qcustomplot"), this);
dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
dock->setWidget(laWidget);
addDockWidget(Qt::BottomDockWidgetArea, dock);
QWidget *centralWidget=new QWidget();
setCentralWidget(centralWidget);
}
};
Here is a minimum example done directly in mainwindow.h. A dock with a central widget and a QDockWidget with a qCustomPlot. I am using the compiled DLL version of qCustomPlot
Image: dock starts with zero height:
Initially the dock looks like this. The plot is hidden and the dock is claiming no height in an otherwise empty layout.
Image: dock stretched to show the plot
The plot is visible when the user stretches the dock.
I strongly suspect there is a way for the dock to adjust to the height of the qCustomPlot automatically. I can set the dock height from code, but that seems like a hack.
The most direct approach to solve your issue might be to define a minimum size for your QCustomPlot Widget. This can easily achieved with the following reduced example. Actually, the problems has nothing to do with QCustomPlot at all. It could have been any kind of widget with minimum size (0,0).
#include <QMainWindow>
#include "qcustomplot.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(){
auto m_customPlot = new QCustomPlot();
m_customPlot->axisRect()->setupFullAxesBox(true);
auto dock = new QDockWidget(tr("qcustomplot"), this);
dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
dock->setWidget(m_customPlot);
m_customPlot->setMinimumSize(QSize(500,500));
dock->setMinimumSize(m_customPlot->minimumSize());
addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, dock);
setCentralWidget(new QWidget);
}
};
A better solution might to save and to restore the geometry of your dock widget configuration in the registry. This leaves the user with just the dock widget configuration that he finds desirable.
void MainWindow::closeEvent(QCloseEvent *event)
{
QSettings settings("MyCompany", "MyApp");
settings.setValue("geometry", saveGeometry());
QMainWindow::closeEvent(event);
}
QSettings settings("MyCompany", "MyApp");
dock->restoreGeometry(settings.value("myWidget/geometry").toByteArray());
How can I make the button go beyond the edge of QToolbar?
Below is the code as I create the toolbar:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0)
private:
QToolBar* _toolBar;
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
_toolBar = new QToolBar;
QAction *actionAdd = new QAction(QIcon(":/images/add.png"), "", this);
_toolBar->addAction(actionAdd);
addToolBar(Qt::ToolBarArea::TopToolBarArea, _toolBar);
}
style.qss
QToolBar {
background: #018ac4;
height: 150px;
}
As said before, it is not possible to solve this correctly using QtWidgets.
However I see two options to visually create that effect:
Take the button out of the tool bar and add it to the main window instead, but do not add it to a layout. Usually i would say reposition it on resize events, but since it is in the top left, you might as well just call setGeometry() once on startup and not worry about it later. You probably have to add last, or call rise() though.
Make it look like the button sticks out, while it really doesn't. Make the toolbar as large as the button, but paint the lower part of the toolbar in the brighter blue, so that it looks like it is part of the widget below it.
It is not possible with widgets. A QWidget can not paint outside of its area. See this answer : https://stackoverflow.com/a/48302076/6165833.
However, the QToolBar is not really the parent of the QAction because addAction(QAction *action) does not take the ownership. So maybe the QMainWindow could paint your QAction the way you want but AFAIK this is not doable through the public API of Qt.
What you could do is use QML (but you would need to use QML for the whole window then).
I just started learning Qt a couple days ago to make a game, and I'm trying to figure out how to make layouts work.
What I want is a Window using QStackedLayout with 2 widgets inside: StartScreen and GameScreen. StartScreen is shown on top on program run. A button in StartScren is connected to a function inside Window, and Window will call setCurrentIndex to change the widget on top to GameScreen.
What happens right now is that when I click on the button, the view changes to a blank window. I've tried hardcoding to setCurrentIndex(0), which does nothing, setCurrentIndex(1), which is what GameScreen should be and displays the same blank window, and setCurrentIndex(2), which is out of index bounds but still does nothing. So the connection is going through, but I don't understand why a blank window will show up instead of the button I have on GameScreen.
If someone can explain to me what concept I missed and how to fix it, I'd greatly appreciate it. Thanks!
Here is window.cpp:
Window::Window(QWidget *parent) : QWidget(parent)
{
resize(640, 480);
layout = new QStackedLayout;
createStartScreen();
createGameScreen();
setLayout(layout);
show();
};
void Window::createStartScreen(){
start = new StartScreen();
layout->addWidget(start);
start->setWindow(this);
}
void Window::playGame(){
layout->setCurrentIndex(layout->indexOf(game));
}
void Window::createGameScreen(){
game = new GameScreen();
layout->addWidget(game);
}
startscreen.cpp:
StartScreen::StartScreen(QWidget *parent) : QWidget(parent)
{
newGameButton = new QPushButton("New Game", this);
newGameButton->setGeometry(QRect(QPoint(260, 300), QSize(120,40)));
quitButton = new QPushButton("Quit", this);
quitButton->setGeometry(QRect(QPoint(260, 360), QSize(120,40)));
connect(quitButton, SIGNAL(clicked()), QApplication::instance(), SLOT(quit()));
};
void StartScreen::setWindow(Window *w){
connect(newGameButton, SIGNAL(clicked()), w, SLOT(playGame()));
}
gamescreen.cpp:
GameScreen::GameScreen(QWidget *parent) : QWidget(parent)
{
button = new QPushButton("Hi");
button->setGeometry(QRect(QPoint(260, 260), QSize(120,40)));
};
That's because you don't call show on button. But you should rather use a layout to handle it.
e.g.:
GameScreen::GameScreen(QWidget *parent)
: QWidget(parent)
{
button = new QPushButton(tr("Hi"));
QHBoxLayout *layout = new QHBoxLayout(this);
layout->addWidget(button);
};
button will have a size adapted to its text and will be cleaned positioned in GameScreen.
On a side note, you should rather add a signal to StartScreen to request a new game and do the connection in Window. That way you won't have a tight coupling between StartScreen and Window.
Here is what I am doing: mainwindow with MdiArea, and I add a scrollarea widget (which contains a image label) to MdiArea as a subwindow. It doesn't work (the picture doesn't show).
Here is my code:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QScrollArea sa;
QPixmap *image = new QPixmap("2.jpg");
QLabel* imageLabel = new QLabel();
imageLabel->setPixmap(*image);
sa.setWidget(imageLabel);
sa.show();
ui->mdiArea->addSubWindow(&sa);
}
But when I use a QLabel as subwindow directly, i.e. replace the last line with:
ui->mdiArea->addSubWindow(imageLabel);
it works perfectly.
Anyone know why this is happening?
QScrollArea sa;
This declares a QScrollArea on the stack. It gets destroyed immediately after the constructor finishes. Allocate it with new like you do for the other widgets and it should start working.
QScollArea *sa = new QScrollArea;
...
ui->mdiArea->addSubWindow(sa);
(And change the sa. to sa->.)