How to move qwidget on Graphics View? - qt

On a QGraphicsView I set a QGraphicsScene. I add a QDial object through a QGraphicsProxy widget. How to move the QDial object?
QDial *dial = new QDial;// dial object
dial->setGeometry(event->pos().x(),event->pos().y(),80,80);// placing on mouse position
QSizeGrip * sizeGrip = new QSizeGrip(dial);
QHBoxLayout *layout = new QHBoxLayout(dial);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(sizeGrip, 0, Qt::AlignRight | Qt::AlignBottom);
QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget();
proxy->setWidget(dial);
proxy->setFlag(QGraphicsItem::ItemIsMovable,true);
scene->addItem(proxy);

In this code QGraphicsWidget is GraphicItem by making parent of widget you can move widget on scene.setflags movable.
QDial *dial = new QDial;// dial object
dial->setGeometry(event->pos().x(),event->pos().y(),80,80);// placing on mouse position
QSizeGrip * sizeGrip = new QSizeGrip(dial);
QHBoxLayout *layout = new QHBoxLayout(dial);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(sizeGrip, 0, Qt::AlignRight | Qt::AlignBottom);
QGraphicsWidget* parentWidget = new QGraphicsWidget();//make parent of widget
parentWidget->setCursor(Qt::SizeAllCursor);
parentWidget->setGeometry(event->scenePos().x(),event->scenePos().y(),width.toInt(), height.toInt());
parentWidget->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable );
addItem(parentWidget);
QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget();
proxy->setWidget(dial);
proxy->setParentItem(parentWidget);

Putting the QDial into a QGraphicsProxyWidget is only the first step.
Since the proxy does not support moving, you can put it into a QGraphicsItem (e.g. a rect) and use this to move the proxy with the QDial in it:
QDial *dial = new QDial();
QGraphicsRectItem* movableGraphicsItem = scene->addRect(event->pos().x(), event->pos().y(), 80, 80);
movableGraphicsItem->setFlag(QGraphicsItem::ItemIsMovable, true);
movableGraphicsItem->setFlag(QGraphicsItem::ItemIsSelectable, true);
QGraphicsProxyWidget* proxy = scene->addWidget(dial);
proxy->setPos(event->pos().x(), event->pos().y() + movableGraphicsItem->rect().height());
proxy->setParentItem(movableGraphicsItem);
movableGraphicsItem->setRotation(180); // Test by rotating the graphics item
I have not tested this, you may have to play around with the sizing, the position and the layout and size grip you are using, but this is the base from where you can start.

Related

Adding label to video

I have to write a simple video player that can display some subtitles,link or a picture(like on YouTube) in a certain time. I have no idea of how do display anything using QVideoWidget. I couldn't find any useful class to do it. Could you please give me some advices?
I did It your way but after i load any video QLabel disappears...
player->setVideoOutput(vw);
playlistView->setMaximumWidth(200);
playlistView->setMinimumWidth(300);
window = new QWidget;
Playerlayout = new QGridLayout;
subtitleWidget = new QLabel;
subtitleWidget->setMaximumWidth(1000);
subtitleWidget->setMaximumHeight(100);
subtitleWidget->setStyleSheet("QLabel {background-color : red; color
blue;}");
subtitleWidget->setAlignment(Qt::AlignCenter | Qt::AlignBottom);
subtitleWidget->setWordWrap(true);
subtitleWidget->setText("example subtitle");
Playerlayout->addWidget(vw,0,0);
Playerlayout->addWidget(subtitleWidget,0,0);
Playerlayout->addWidget(playlistView,0,1,1,2);
If QVideoWidget doesn't provide what you require directly then you could always set up an overlay.
The basic layout item hierarchy would be something like...
QWidget
layout
QVideoWidget
subtitle_widget
In this case the layout could be either a QStackedLayout using stacking mode QStackedLayout::StackAll or a QGridLayout with both the QVideoWidget and the subtitle_widget occupying the same cells but with the correct z-order.
Going with the QGridLayout...
auto *w = new QWidget;
auto *l = new QGridLayout(w);
auto *video_widget = new QVideoWidget;
auto *subtitle_widget = new QLabel;
/*
* Subtitles will be shown at the bottom of the 'screen'
* and centred horizontally.
*/
subtitle_widget->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
subtitle_widget->setWordWrap(true);
/*
* Place both the video and subtitle widgets in cell (0, 0).
*/
l->addWidget(video_widget, 0, 0);
l->addWidget(subtitle_widget, 0, 0);
Subtitles etc. can now be displayed simply by invoking subtitle_widget->setText(...) at the appropriate time.
The same method can easily be extended to overlaying other types of information.

Stop QWidgets from stacking on top of each other dynamically

I create all my QWidgets with code and put them in a tab. However all of the widgets are stacked on top of each other. Is there a way to move widgets dynamic?. It would be possible to move the widgets dynamic to how many there already is in the widget?.As it is know I have to move them with move() which could be hard to keep track on when more objects are added.
QTabWidget* MainWindow::CreateTabWidget(){
QTabWidget* tabWidget = new QTabWidget(ui->centralWidget);
tabWidget->setFixedSize(this->size().width(),this->size().height()- 40);
QWidget* tab = new QWidget();
QLabel* label = new QLabel("Sektionnamn",tab);
QLineEdit* line = new QLineEdit(tab);
line->move(0,20);
tabWidget->addTab(tab,"Tab 1");
return tabWidget;
}
Use QLayout:
QLabel* label = new QLabel("Sektionnamn");
QLineEdit* line = new QLineEdit();
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(label);
layout->addWidget(line);
tab->setLayout(layout);

Qt: what layout or combination of layout should use in this case?

I am working on a Qt Project and for this project I require to design something like this:
I have designed so far in Qt Creator and I have the component ready, but when I am trying to add widget in different layouts, I am not getting the shapes I want. What should I do to make my application resizable?
Catches:
Sidebar has fixed width, which means for horizontal increment of window size the sidebar's horizontal width won't increase. Sidebar itself is a widget.
upperbar's vertical width is fixed (if possible). Which means, during vertical window size increment the upperbar can't become vertically wider. And it itself is also a widget.
the widgets by the side of sidebar are in a qstackedwidget.
Nested layouts:
(green square = QStackedWidget)
Steps:
[Definition]
H(x, y, ...) = horizontal layouts on x, y, ...; where x, y, ... are widget(W#) or Layout(L#)
V(x, y, ...) = horizontal layouts on x, y, ...; where x, y, ... are widget(W#) or Layout(L#)
Step 1: V(W1, W2) = L1
Step 2: H(W3, L1) = L2
Step 3: V(W4, L2) = L3
Step 4: Set L3 as the layout of current page of the StackedWidget layout
Step 5: H(W5, StackedWidget) = L4
Step 6: H(W6, a spacer, W7) = L5
Step 7: V(L5, L4)
Notice that W6 and W7 are fixed in horizontal size (or set maximum on it), the spacer between them acts as the only resizable widget in the layout L5.
And here is the hierarchy:
Just for fun, the code version, with minimal optimized code...
#include "mainwindow.h"
#include <QBoxLayout>
#include <QLabel>
#include <QStackedWidget>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// Ingredients (taken from the mockup from top-left to bottom-right)
QFrame *upperBar = new QFrame;
QLabel *upperIcon = new QLabel("icon");
QLabel *profilePicture = new QLabel("profile picture");
QFrame *sideBar = new QFrame;
QLabel *sideItemA = new QLabel("Item A");
QLabel *sideItemB = new QLabel("Item B");
QStackedWidget *contentStack = new QStackedWidget;
QFrame *contentPage1 = new QFrame;
QLabel *page1WidgetA = new QLabel("I am widget A");
QLabel *page1WidgetB = new QLabel("I am widget B");
QLabel *page1WidgetC = new QLabel("I am widget C");
QLabel *page1WidgetD = new QLabel("I am widget D");
QWidget *centralWidget = new QWidget;
// The needed layouts:
QHBoxLayout *upperBarLayout = new QHBoxLayout;
QVBoxLayout *sideBarLayout = new QVBoxLayout;
QGridLayout *page1GridLayout = new QGridLayout;
QGridLayout *centralLayout = new QGridLayout;
// Let's connect the pieces:
/* First we setup the upperbar: */
upperBarLayout->addWidget(upperIcon, 1, Qt::AlignLeft);
upperBarLayout->addWidget(profilePicture, 3, Qt::AlignRight);
upperBar->setLayout(upperBarLayout);
upperBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
/* Then we setup the sidebar: */
sideBarLayout->addWidget(sideItemA);
sideBarLayout->addWidget(sideItemB);
sideBarLayout->addStretch();
sideBar->setLayout(sideBarLayout);
sideBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
/* Then we setup the content stacked widget */
page1GridLayout->addWidget(page1WidgetA, 0, 0, 3, 1);
page1GridLayout->addWidget(page1WidgetB, 0, 1, 1, 1);
page1GridLayout->addWidget(page1WidgetC, 1, 1, 2, 1);
page1GridLayout->addWidget(page1WidgetD, 3, 0, 1, 2);
contentPage1->setLayout(page1GridLayout);
contentStack->addWidget(contentPage1);
contentStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
/* Finally we setup the main elements into the central layout... */
centralLayout->addWidget(upperBar, 0, 0, 1, 2);
centralLayout->addWidget(sideBar, 1, 0, 1, 1);
centralLayout->addWidget(contentStack, 1, 1, 1, 1);
centralWidget->setLayout(centralLayout);
setCentralWidget(centralWidget);
/* Let's color it a little to better realize the positioning: */
setStyleSheet("QWidget {"
"border: 1px solid black;"
"color: red"
"}");
}
MainWindow::~MainWindow()
{
}
Here is the result:

How to delete a space between QLabel and QLineEdit

I want to reduce space between label and QLineEdit (QLabel is above QLineEdit). How can I achieve it? In the code I'm creating items, that I later put in some layouts.
QLabel* lgamma = new QLabel("Gamma");
gamma = new QLineEdit();
QLabel* lmin_linie = new QLabel(QString::fromUtf8("Min. il. zmian linii"));
min_lin = new QLineEdit();
// ...
QLabel* lmax_kursy = new QLabel(QString::fromUtf8("Max zm. il. kursów"));
max_kursy = new QLineEdit();
QGridLayout *lay = new QGridLayout(this);
QVBoxLayout *box1 = new QVBoxLayout();
QVBoxLayout *box2 = new QVBoxLayout();
// ...
QVBoxLayout *box12 = new QVBoxLayout();
box1->addWidget(lmin_linie);
box1->addWidget(min_lin);
box2->addWidget(lmax_lin);
box2->addWidget(max_lin);
// ...
box12->addWidget(literacje);
box12->addWidget(iteracje);
verticalColumn1->addLayout(box1);
verticalColumn1->addLayout(box2);
// ...
verticalColumn3->addLayout(box12);
start = new QPushButton("Start", this);
QHBoxLayout *corn = new QHBoxLayout();
corn->addLayout(verticalColumn1);
corn->addLayout(verticalColumn2);
corn->addLayout(verticalColumn3);
QVBoxLayout *rup = new QVBoxLayout();
rup->addLayout(corn);
rup->addWidget(start);
You can simply add a spacer to your layout.
QSpacerItem *spacer = new QSpacerItem(1, 50, QSizePolicy::Ignored, QSizePolicy::Expanding);
box1.addItem(spacer);
Adapt the args or QSpacerItem for your needs, for examle QSizePolicy::Preferred could be better than QSizePolicy::Expanding, and reduce the preferred height (second argument).
Why don't you use the easy way to do that GUI with Qt designer ?
You can try to set QLabel and QLineEdit border:
lmax_kursy->setStyleSheet("border-width:0px");
max_kursy->setStyleSheet("border-width:0px");
or set spacing in layout. First check what is a current value of spacing:
box1->spacing();
If it's 0, try to set negative value like -2:
box1->setSpacing(-2); // or 0 or something else

QScrollArea not respecting contentMargins setting

QScrollArea, for some reason, is ignoring the contentMargins setting when I set QGraphicsView as its widget. Looking at the snippet below, can someone please tell if I'm doing something wrong or it could be a bug in the SDK?
Snippet 1 (works perfect):
QWidget *appWindow = new QWidget;
QScrollArea *sa = new QScrollArea(appWindow);
sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
sa->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
sa->setContentMargins(50, 50, 50, 50);
QWidget *widgetToScroll = new QWidget(sa);
widgetToScroll->resize(5000, 5000);
sa->setWidget(widgetToScroll);
QVBoxLayout *appWindowLayout = new QVBoxLayout(appWindow);
appWindowLayout->addWidget(sa);
appWindow->setLayout(appWindowLayout);
appWindow->show();
Snippet 2 (It's like setContentMargins() call is ignored completely):
QWidget *appWindow = new QWidget;
QScrollArea *sa = new QScrollArea(appWindow);
sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
sa->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
sa->setContentMargins(50, 50, 50, 50);
QGraphicsView *widgetToScroll = new QGraphicsView(new QGraphicsScene(sa), sa);
widgetToScroll->setAlignment(Qt::AlignLeft | Qt::AlignTop);
widgetToScroll->resize(5000, 5000);
sa->setWidget(widgetToScroll);
QVBoxLayout *appWindowLayout = new QVBoxLayout(appWindow);
appWindowLayout->addWidget(sa);
appWindow->setLayout(appWindowLayout);
appWindow->show();
Thanks.
To make the content margins work properly for a QScrollArea widget I subclass it and manually set the viewport margins (which is a protected method in QT 4.7)
// Extended class
class QScrollAreaWithMargins : public QScrollArea
{
public:
virtual void resizeEvent(QResizeEvent *event) override
{
// Define content margins here
setViewportMargins(5, 0, 0, 0); // <<<<< SET MARGINS HERE
QScrollArea::resizeEvent(event);
}
};
// Usage
//...
mEditorScrollArea = new QScrollAreaWithMargins();
//...
It looks like you are confusing the structure of how to nest a QGraphicsView and a QGraphicsScene. (Maybe it was just a typo?)
QGraphicsView *widgetToScroll = new QGraphicsView(new QGraphicsScene(sa), sa);
should be changed to
QGraphicsView *widgetToScroll = new QGraphicsView(new QGraphicsScene(), sa);
or
QGraphicsView *widgetToScroll = new QGraphicsView();
sa->setWidget(widgetToScroll);
When you add a QWidget to a layout, you change the widget's parent. When you set a widget (or QGraphicsView) to a QScrollArea, you change that widget's parent. See Object Trees & Ownership for more information. So if you wanted to set up your QGraphicsView inside a QScrollArea your code would look like this:
QWidget *appWindow = new QWidget;
QScrollArea *sa = new QScrollArea(); // No need to specify a parent here if
// you add it to a layout later
sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
sa->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
sa->setContentsMargins(50, 50, 50, 50);
QGraphicsView *widgetToScroll = new QGraphicsView();
widgetToScroll->setAlignment(Qt::AlignLeft | Qt::AlignTop);
widgetToScroll->resize(5000, 5000);
sa->setWidget(widgetToScroll); // This sets the parent for widgetToScroll
QVBoxLayout *appWindowLayout = new QVBoxLayout();
appWindowLayout->addWidget(sa); // This sets the parent for sa
appWindow->setLayout(appWindowLayout); // This sets the parent for appWindowLayout
appWindow->show();
As a side note...
When using QGraphicsViews with a QGraphicsScene, instead of setting the margins using a QScrollArea's setContentsMargins, I use the QGraphicsView automatic scrolling and just set the scene rect to have a larger margin that the size of my content like so:
QWidget *appWindow = new QWidget;
QGraphicsView *widgetToScroll = new QGraphicsView();
QGraphicsScene *scene = new QGraphicsScene();
scene->addRect(0,0, 5000, 5000);
widgetToScroll->setSceneRect(-50,-50, 5050, 5050);
widgetToScroll->setScene(scene);
QVBoxLayout *appWindowLayout = new QVBoxLayout(appWindow);
appWindowLayout->addWidget(widgetToScroll);
appWindow->setLayout(appWindowLayout);
appWindow->show();
The QGraphicsView includes quite a bit more than just automatic scrolling when needed. You can resize everything inside of it and quite a bit more. It is great for 2D layouts, interactions and animations. See Qt's Graphics View Framework at http://doc.qt.io/qt-5/graphicsview.html for more information.
Here is more information that may be useful when using margins and paddings: The Box Model used by QStyleSheets.

Resources