QScrollArea derivative is empty if it's created from an .ui file - qt

Consider following simple example:
Area.hh
#pragma once
class Area;
#include <QScrollArea>
class Area : public QScrollArea {
Q_OBJECT
public:
Area (QWidget *_parent = 0);
};
Area.cc
#include "main.hh"
#include "Area.hh"
#include <QLabel>
Area::Area (QWidget *_parent) :
QScrollArea (_parent)
{
QLabel *label = new QLabel ("Show me please");
setWidget (label);
}
This scroll area should show a label inside it. And it does so well if you just create an Area object and show it like this:
Area *area = new Area();
area->show();
However, if you add a QScrollArea with Qt Creator and promote it to Area class, then it shows nothing inside and there are no scrollbars. What can I do to show it properly?

Qt Designer adds an empty widget inside the QScrollArea, overwriting yours.
To prevent that, use a base QWidget instead of a QScrollArea, and promote that widget to an Area class. Qt's Ui compiler won't considered it to be a QScrollArea, so it won't generate a call to setWidget anymore.

Related

How to make QToolButton go beyond the edge of QToolbar?

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

Controlling number of boxes in box plot with Qt Chart

I am trying to figure out how to control number of boxes (or box sets) in the box plot with Qt chart, and use scrollbar to scroll through the whole chart. It's similar to this example (http://www.advsofteng.com/doc/cdcppdoc/zoomscrolltrackqt.htm).
The code below is what I did, and it populates all the boxes in the chartview, no matter how many. I selected 'ScrollBarAsNeeded' for the vertical and horizontal scroll bar policies in Qt designer.
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QChartView>
#include <QBoxPlotSeries>
#include <QBoxSet>
#include <QValueAxis>
#include <QBarCategoryAxis>
#include <QtSql>
#include <QSqlDatabase>
#include <QSqlQuery>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
db.setHostName("192.168.2.103");
db.setPort(5433);
db.setUserName("vorlket");
db.setPassword("K1156312j");
db.setDatabaseName("fxproj");
QBoxPlotSeries *bidaskSeries = new QBoxPlotSeries(this);
bidaskSeries->setName("bidask");
QStringList categories;
if (db.open())
{
QSqlQuery query;
if (query.exec("SELECT EXTRACT(YEAR FROM month), EXTRACT(MONTH FROM month), bid_low, bid_lowquartile, bid_median, bid_upquartile, bid_high FROM audusd.ts_month_quotebid ORDER BY month"))
{
while (query.next())
{
categories << query.value(0).toString() + "-" + query.value(1).toString();
QBoxSet *set = new QBoxSet();
set->setValue(QBoxSet::LowerExtreme, query.value(2).toDouble());
set->setValue(QBoxSet::LowerQuartile, query.value(3).toDouble());
set->setValue(QBoxSet::Median, query.value(4).toDouble());
set->setValue(QBoxSet::UpperQuartile, query.value(5).toDouble());
set->setValue(QBoxSet::UpperExtreme, query.value(6).toDouble());
bidaskSeries->append(set);
}
}
db.close();
}
QChart *chart = new QChart();
chart->legend()->hide();
chart->addSeries(bidaskSeries);
QBarCategoryAxis * axisX = new QBarCategoryAxis();
axisX->append(categories);
chart->addAxis(axisX, Qt::AlignBottom);
chart->setAxisX(axisX, bidaskSeries);
QValueAxis *axisY = new QValueAxis();
chart->addAxis(axisY, Qt::AlignLeft);
chart->setAxisY(axisY, bidaskSeries);
axisY->setRange(0.65, 1.15);
ui->chartview->setChart(chart);
ui->chartview->setRenderHint(QPainter::Antialiasing);
}
MainWindow::~MainWindow()
{
delete ui;
}
Maybe I need to use QGraphicsScene, instead of QChartView.
http://doc.qt.io/qt-5/qchartview.html#details:
QChartView is a standalone widget that can display charts. It does not require separate QGraphicsScene to work. If you want to display a chart in your existing QGraphicsScene, you need to use the QChart (or QPolarChart) class instead.
http://doc.qt.io/qt-5/qgraphicsscene.html#details:
The QGraphicsScene class provides a surface for managing a large number of 2D graphical items.
The class serves as a container for QGraphicsItems. It is used together with QGraphicsView for visualizing graphical items, such as lines, rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is part of the Graphics View Framework.
QGraphicsScene also provides functionality that lets you efficiently determine both the location of items, and for determining what items are visible within an arbitrary area on the scene. With the QGraphicsView widget, you can either visualize the whole scene, or zoom in and view only parts of the scene.

Basic Qt layout: Adding to a frame

I am just staring Qt, so hopefully is a rookie question. Working in Qt Creator 2.7.2, Qt 5, standard desktop app.
Currently my app is one window, with the main window entirely taken up by a console object, with is just a plain text edit, like this:
setCentralWidget(console);
Which of course takes up the entire window. So I added a frame using the UI editor, frame_2. How do I get the console to appear inside the frame, instead of taking up the whole window?
http://qt-project.org/doc/qt-4.8/designer-layouts.html
http://qt-project.org/doc/qt-4.8/layout.html
Your central widget is just QWidget, and then it needs a layout. You drag a layout into it, and there are some buttons across the top of Qt Designer for turning on and off the layout.
When setupUi is called, it already does the setCentralWidget call for you. If you call it yourself you lose all you gained from using Qt Designer.
ui->setupUi(this);
If you are using Qt Designer, you should not edit any generated files. If you edit the .ui file again, it may generate the ui_.h file for you again and fix the problem.
Here is an example of the generated file ui_mainwindow.h:
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created: Wed Jul 10 15:48:32 2013
** by: Qt User Interface Compiler version 4.8.4
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHeaderView>
#include <QtGui/QMainWindow>
#include <QtGui/QMenuBar>
#include <QtGui/QStatusBar>
#include <QtGui/QToolBar>
#include <QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QMenuBar *menuBar;
QToolBar *mainToolBar;
QWidget *centralWidget;
QStatusBar *statusBar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(400, 300);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
MainWindow->addToolBar(mainToolBar);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
// !!!!! NOTE !!!!! setCentralWidget gets called
MainWindow->setCentralWidget(centralWidget);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
MainWindow->setStatusBar(statusBar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
I also rambled about using Layouts on a previous post:
Add QRadioButton into QWidget without layout
Hope that helps.

Qt::Pixmap in Qwidget doesn't show up in MainWindow

Here is another newbie to Qt.
What I need to do is to have a scrollable Area in the center of MainWindow, which displays images, and allows user to paint on the image.
Since I cannot add a QPixmap directly to a scrollable Area, I tried to create a subclass of QWidget, like below:
class Canvas: public QWidget
{
public:
Canvas(){
image = new QPixmap(480,320);
image->fill(Qt::red);
}
QPixmap *image;
};
Then I declared Canvas *c in the header file.
In the implementation, I wrote:
canvas = new Canvas;
setCentralWidget(canvas);
However, apparently this does not help to show up the QPixmap. I do not know what to do.
You don't need to subclass QWidget for this. QPixmap is not a widget, so it is not shown anywhere. You need to add your pixmap to some widget, this will work:
in header:
QLabel* imageLabel;
in cpp:
imageLabel = new QLabel(this);
QPixmap image(480,320);
image.fill(Qt::red);
imageLabel->setPixmap(image);
setCentralWidget(imageLabel);

Qt alignment in QGridLayout eliminates the resizing of its elements

Ok, so basically I have a simple table with a QWidget and two buttons as shown below:
QGridLayout *layout = new QGridLayout;
layout->addWidget(viewcontainer,0,0,1,2);
layout->addWidget(reset,1,0);
layout->addWidget(done,1,1);
This is basically what I want, where "reset" and "done" are buttons. Essentially it's a QWidget, viewcontainer, which resizes as the window size is changed by the user while the buttons' heights remains the same. But, the default for the gridlayout is to align the contents to the left. If I change this with:
layout->addWidget(viewcontainer,0,0,1,2, Qt::AlignCenter);
It does sort of what I want, but the graphicsscene no longer resizes (remains a small constant size). I'd like to retain the resizing while just aligning the widget to the center. Thanks.
I think the easiest solution which provides a clean solution is to nest 2 layouts.
Your 'outer' (parent) layout should be a QHBoxLayout and you can add your QGridLayout into it as an 'inner' (child) layout with addLayout().
Based on my experience you should avoid to set Qt::Alignment every time you can. It can really mess up your layout. For simple layouts it can work but for more complex ones you should avoid it. And you never know that you should extend your layout in the future or not so my suggestion is to use nested layouts.
Of course you can create a QWidget for the 'outer' layout and for the 'innser' layout as well but most of the times it should be fine to just nest 2 layouts.
Also you can use QSpacerItem to fine-tune your layout.
Have a look at this example code, I think it does what you want:
#include <QApplication>
#include <QPushButton>
#include <QGraphicsView>
#include <QGridLayout>
#include <QPalette>
class MyWidget : public QWidget
{
public:
MyWidget()
{
QGridLayout * layout = new QGridLayout(this);
QGraphicsView * gv = new QGraphicsView;
layout->addWidget(gv, 0,0, 1,2);
layout->setRowStretch(0, 1); // make the top row get more space than the second row
layout->addWidget(new QPushButton("reset"), 1,0);
layout->addWidget(new QPushButton("done"), 1,1);
}
};
int main(int argc, char ** argv)
{
QApplication app(argc, argv);
MyWidget w;
w.show();
return app.exec();
}

Resources