How to get coordinates QScrollArea child widget? - qt

How to get coordinates QScrollArea child widget?
mainWindow::mainWindow( QWidget *parent)
{
// class PaintWidget:public QScrollArea
PaintWidget *painter = new PaintWidget( this, &manager);
setCentralWidget( painter );
//some code
}
PaintWidget::PaintWidget( QWidget *parent, plugin::PluginsManager *manager):
painter(manager, this)
{
// RPW painter;
// class Painter:public QGLWidget
setWidget( &painter );
setAlignment( Qt::AlignCenter );
//some code
}

QWidget::pos() is what you're looking for. It applies in all cases, QScrollWidget does not require special treatment here at all.

Related

How to properly delete items from the QWidget

This is the code for populating and deleting item from the QWidget.
class ShowCommands : public QWidget
{
private:
QWidget wdg;
QVBoxLayout m_layout;
QScrollArea* m_area;
QWidget m_contents;
QVBoxLayout m_contentsLayout;
bool isWrite;
public:
ShowCommands(QWidget *parent = nullptr);
void showWindow();
void setParent(QWidget* par);
void AddCommand(std::string stdstrCommand);
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ShowCommands::ShowCommands(QWidget *parent) : QWidget(parent)
{
isWrite = true;
m_area = new QScrollArea;
m_contents.setLayout(&m_contentsLayout);
m_layout.addWidget(m_area);
m_area->setWidget(&m_contents);
m_contentsLayout.setSizeConstraint(QLayout::SetMinimumSize);
wdg.setLayout(&m_layout);
wdg.setFixedWidth(650);
wdg.setWindowTitle("Commands");
wdg.setWindowFlags(Qt::Window
| Qt::FramelessWindowHint);
wdg.hide();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ShowCommands::showWindow()
{
if (isWrite == false)
{
if (m_contentsLayout.layout() != NULL)
{
QLayoutItem* item;
while ((item = m_contentsLayout.layout()->takeAt(0)) != NULL)
{
delete item->widget();
delete item;
}
}
isWrite = true;
wdg.show();
// AddCommand() function is called now multiple times and items are populated.
}
else
{
isWrite = false;
wdg.hide();
}
}
void ShowCommands::AddCommand(std::string stdstrCommand)
{
if (isWrite)
{
QLabel *label = new QLabel;
label->setText(stdstrCommand.c_str());
m_contentsLayout.addWidget(label);
}
}
In the showWindow() function first all of the items of widget are deleted and than populate the widget with new items.
The issue is that after i delete the existing items the new items are not populated from top to bottom but they start appearing from center.
I see many problems with your code, some of them make it hard to read, but anyway I think the main problem here is how properly create those items ...
You should create your widgets as pointers and assign good parenting to them, unparented widgets will create a new window. You should do something like this.
class MyWidget: public QWidget
{
Q_OBJECT
public;
MyWidget(QWidget *parent=nullptr) : QWidget(parent)
{
w1=new QWidget(this);
}
private:
class QWidget *m_w1;
}
that way you will have a child widget that will be drawn relative to you in the same window. You can add a layout to your widget, and then add your widgets to it so it handles the location for you. ie:
class MyWidget: public QWidget
{
Q_OBJECT
public;
MyWidget(QWidget *parent=nullptr) : QWidget(parent)
{
//passing this to the construct assign layout to 'this' widget
QVBoxLayout *verticalLayout=new QVBoxLayout(this);
w1=new QWidget(this);
w2=new QWidget(this);
verticalLayout->addWidget(w1);
verticalLayout->addWidget(w2);
}
private:
class QWidget *m_w1;
class QWidget *m_w2;
}
in that case both widgets will be display one below the other in the space assigned to you. Also the space assigned to you will depend on the characteristics of the two child widgets (you probably will create something derived from QWidget).
Now about the QScrollArea, that widget it is meant to be used with a widget placed 'inside', and you should add items to the layout of that one. ie:
class MyWidget: public QWidget
{
Q_OBJECT
public;
MyWidget(QWidget *parent=nullptr) : QWidget(parent)
{
//passing this to the construct assign layout to 'this' widget
QVBoxLayout *verticalLayout=new QVBoxLayout(this);
m_scroll=new QScrollArea(this);
verticalLayout->addWidget(m_scroll);
m_containerwidget=new QWidget(this);
//this sets our container widget as the inside's scrollarea widget
m_scroll->setWidget(m_containerwidget);
//if your widget will resize along the way you use this, in your case you do
m_scroll->setWidgetResizable(true);
m_containerLayout=new QVBoxLayout (m_containerwidget);
m_w1=new QWidget(this);
m_w2=new QWidget(this);
m_containerLayout->addWidget(m_w1);
m_containerLayout->addWidget(m_w2);
}
private:
class QScrollArea *m_scroll;
class QWidget *m_containerwidget;
class QVBoxLayout *m_containerLayout;
class QWidget *m_w1,m_w2;
}
You don't usually store all that information (m_containerLaoyut,m_containerWidget) in the class as you can query the objects for them, but just for clarity I add them there.
The last example applies to your scenario, you could store your 'items widgets' in a list, or query the layout for them, and when you need to delete them you just do that and then add new ones to the layout.
Of course you can use any kind of layout, I used vertical just as an example.

How to make a QTextDocument as a widget?

I need to build a widget, which bases on QTextDocument.
MyWidget.h
class MyWidget: public QFrame
{
public:
explicit MyWidget( QWidget *p_parent );
private:
QTextDocument m_textDocument;
};
MyWidget.cpp
MyWidget::MyWidget( QWidget *p_parent ) : QFrame( p_parent )
{
QVBoxLayout *layout = new QVBoxLayout( this );
layout->setMargin( 0 );
layout->setSpacing( 0 );
m_textDocument = new QTextDocument( this );
layout->addWidget( m_textDocument ); // does not work
layout->addLayout(m_textDocument->documentLayout()); // I have tried this, but incompatible
}
I can not addWidget because QTextDocument is an object. How can I do to build my widget?
You don't use a QTextDocument as a widget, because a Document is the idea in memory of what a document is, it does not have a Graphicsl Representation.
If you are looking for a Visual representation of a Document, you can use QTextEdit as follows:
auto *textEdit = new QTextEdit(parent);
textEdit->setDocument(myTextDocument);
layout->addWidget(textEdit);

Qt placing widget on custom place

I need to place(programmaticaly) my custom widget in specified place in my MainWindow.
On screenshoot I've marked red rectangle "widget" on place where I want to place my widget. I want place widget on top of QmenuBar and QToolBar.
I've tried setCentralWidget, but it expands widget on whole window.
Image presenting my problem
Code of my widget:
timers.cpp
#include "QtWidgets"
#include "timers.h"
static QLabel *createDragLabel(const QString &text, QWidget *parent)
{
QLabel *label = new QLabel(text, parent);
label->setAutoFillBackground(true);
label->setFrameShape(QFrame::Panel);
label->setFrameShadow(QFrame::Raised);
return label;
}
Timers::Timers(QWidget *parent) : QWidget(parent)
{
QLabel *wordLabel = createDragLabel("dupppa", this);
}
mainwindow.cpp
MainWindow::MainWindow()
{
initMenu();
initButtons();
TrackWindow *trackWindow = new TrackWindow();
setCentralWidget(trackWindow);
Timers *firstTimer = new Timers();
//setCentralWidget(firstTimer); // suck
}
Ok, here is a solution: make MainWidget to be a parent of your widget but do not add it to parent layout. Then basically move your widget with QWidget::move() and and set its size with QWidget::resize(). This way you get a widget with absolute location.
An extract of working code:
#include <QLayout>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow{ parent },
ui{ new Ui::MainWindow }
{
ui->setupUi(this);
menuBar = new QMenuBar { this };
toolBar = new QToolBar { this };
textEdit = new QTextEdit { this };
menuBar->addMenu("File");
menuBar->addMenu("Edit");
menuBar->addMenu("About");
toolBar->addAction("Copy");
toolBar->addAction("Cut");
toolBar->addAction("Insert");
toolBar->addAction("Other tools");
layout()->setMenuBar(menuBar);
addToolBar(toolBar);
textEdit->setText("Your widget");
textEdit->resize(90, 30);
textEdit->move(250, 10);
}
A screenshot:

Subclassed QWidget does not move correctly

I have subclassed QWidget as follows:
class myClass : public QWidget
{
public:
explicit myClass(QWidget *parent);
protected:
void paintEvent(QPaintEvent *event);
}
myWidget::myWidget(QWidget* parent) : QWidget(parent)
{
setGeometry(10,10,100,100);
}
void myWidget::paintEvent(QPaintEvent *event)
{
QPainter qp(this);
QBrush bBlue(QColor::blue);
qp.fillRect(geometry(), bBlue);
}
What I wanted was to create a blue background QWidget placed onto the QWidget parent at 10,10 of size 100,100.
What I'm getting is a default size for myWidget of something like 100,50 at 0,0 with a black background (or transparent) and a blue rectangle starting at 10,10 within myWidget and clipped by myWidget.
It's like the setGeometry moved a rectangle within myWidget, not the myWidget itself.
Fairly new to Qt and would love an explanation and fix of above...
Thank you in advance.
Gary.
...here is actual code:
this is myWidget
class piTemplateWidget : public QWidget
{
public:
explicit piTemplateWidget(QWidget* parent);
static QColor* white;
static QColor* black;
static QColor* lightGrey;
static QColor* lightGreen;
piTemplate* tplt;
protected:
void paintEvent(QPaintEvent *event);
};
QColor* piTemplateWidget::white = new QColor(15,15,15);
QColor* piTemplateWidget::black = new QColor(250,250,250);
QColor* piTemplateWidget::lightGrey = new QColor(100,100,100);
QColor* piTemplateWidget::lightGreen = new QColor(250,15,250);
piTemplateWidget::piTemplateWidget(QWidget* parent) : QWidget(parent)
{
tplt = NULL;
move(100,100);
resize(300,240);
}
void piTemplateWidget::paintEvent(QPaintEvent *event)
{
QPainter qp(this);
QBrush bWhite(*white);
qp.fillRect(this->geometry(), bWhite);
// if (tplt==NULL)
// return;
// tplt->render(&qp);
}
...and this is the parent widgets constructor which instantiates my widget
piTemplateEdit::piTemplateEdit(QWidget *parent) :
QWidget(parent),
ui(new Ui::piTemplateEdit)
{
ui->setupUi(this);
currentTemplate = NULL;
if (piTemplate::templates->count()>0)
{
currentTemplate = (piTemplate*)piTemplate::templates->atIndex(0);
}
templateWidget = new piTemplateWidget(this);
templateWidget->tplt = currentTemplate;
}
...I hopes this helps.
Thank you.
Setting the geometry during the constructor may get overridden by the show event that the parent widget calls on it.
A common main function can look like this:
#include <QtGui/QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
// w.showMaxmized(); // This line would trump the "setGeometry() call
// in the constructor
return a.exec();
}
The geometry rect stored in a QWidget is described here:
http://qt-project.org/doc/qt-4.8/application-windows.html
http://qt-project.org/doc/qt-4.8/qwidget.html#pos-prop
I would not use this internal QWidget setting as how you fill your widget. If you do want to store some setting, make a QRect member variable and use that instead.
If you want to fill the entire box of your QWidget with a color you should try something like this:
void myWidget::paintEvent(QPaintEvent *event)
{
QPainter qp(this);
QBrush bBlue(QColor::blue);
qp.fillRect(QRect(0,0, this->width(), this->height()), bBlue);
}
Inside paint functions, they are relative to paintable area you are in.
http://qt-project.org/doc/qt-4.8/qwidget.html#mapTo
And like #LaszloPapp was saying, you need to use resize() and move(). And it wouldn't hurt to throw in a update() call after either one of those.
Also be sure to check out the show() method and all of its "See Also" items.
http://qt-project.org/doc/qt-4.8/qwidget.html#show
http://qt-project.org/doc/qt-4.8/qshowevent.html
If you #include <QShowEvent>, and call resize() when the show event happens, you may be good to go. If you are nesting this widget inside another widget you should look into using the size hint and setFixedSize or using Layouts properly.
http://qt-project.org/doc/qt-4.8/layout.html
Hope that helps.

Basic Qt GUI: QPushButton for Drawing a line

I want to draw a grid (series of lines) when I click the draw button, and I want them to clear when I click the clear button.
I got the grid to appear as a standalone program, but I cannot figure out how to combine it with QPushButton.
I get the following message when clicking on the Draw button while the program is running.
"QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active"
Thank you
#include <QtGui>
#include <QPainter>
#include "myqtapp.h"
// including <QtGui> saves us to include every class user, <QString>, <QFileDialog>,...
myQtApp::myQtApp(QWidget *parent)
{
setupUi(this); // this sets up GUI
// signals/slots mechanism in action
connect( pushButton_draw, SIGNAL( clicked() ), this, SLOT( draw() ) );
connect( pushButton_clear, SIGNAL( clicked() ), this, SLOT( clear() ) );
connect( pushButton_about, SIGNAL( clicked() ), this, SLOT( about() ) );
}
void myQtApp::draw()
{
//draw the grid
int lineSpacing(30),// line spacing in pixels
numberOfLines;
QPen pen(Qt::black, 2, Qt::SolidLine);
QPainter painter(this);
painter.setPen(pen);
//Grid takes up at most a 400x400 area starting at (right 150, down 50) from upper left
numberOfLines = 400/lineSpacing; //Round down grid size to fit in 400x400
for(int i = 0; i<numberOfLines; i++){
painter.drawLine(150, 50+i*lineSpacing, 150+(numberOfLines-1)*lineSpacing, 50+i*lineSpacing);
painter.drawLine(150+i*lineSpacing, 50, 150+i*lineSpacing, 50+(numberOfLines-1)*lineSpacing );
}
}
The problem you are having is because you are trying to draw on the UI using QPainter outside of the paintEvent() call of a widget - from the Qt docs :
The common use of QPainter is inside a widget's paint event: Construct
and customize (e.g. set the pen or the brush) the painter. Then draw.
Remember to destroy the QPainter object after drawing.
If you try and draw on the widget outside of the paintEvent() call, results are unpredictable.
The correct way to do this would be something like this:
// myQtApp.h
class myQtApp : public QWidget
{
Q_OBJECT
public:
myQtApp(QWidget *parent = 0); // Constructor as you have
protected:
void paintEvent(QPaintEvent *event); // This is re-implemented from QWidget
protected slots:
void draw();
private:
bool drawTheLines;
}
and
// myQtApp.cpp
void myQtApp::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
if(drawTheLines)
{
// Do the drawing here - as in your current draw() function
}
QWidget::paintEvent(event); // call the base class so everything else is drawn OK
}
void draw();
{
drawTheLines = true;
update(); // This forces a repaint of the widget with paintEvent()
}

Resources