Qt - How to get real size of maximized window that I have pointer to? - qt

I have a method that get pointer to widget where should be setted some other widgets. I have to resize the main window, where that widget is placed and then I should get the real size of that widget.
I’ve tried to do this like:
void MyClass::setWidgets(QList<QWidget*> list, QWidget *parentWidget)
{
QWidget* mainWindow = parentWidget->window();
mainWindow->showMaximized();
int width = parentWidget->size().width();
int height = parentWidget->size().height();
/*... rest of method...*/
}
That method is call from other class.
But I read that I should wait for resizeEvent. Could anyone explain me how I should do this or if there is any option to get that size differently?

If you want to get events for a different object, you can install an event filter using QObject::installEventFilter.
A simple example for ResizeEvent is:
filter.hpp
#ifndef FILTER_HPP
#define FILTER_HPP
#include <QtGui>
class ResizeFilter : public QObject
{
Q_OBJECT
public:
ResizeFilter();
protected:
bool eventFilter(QObject *obj, QEvent *event);
};
#endif
filter.cpp
#include "filter.hpp"
ResizeFilter::ResizeFilter() : QObject() {}
bool ResizeFilter::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Resize)
{
QResizeEvent* resizeEv = static_cast<QResizeEvent*>(event);
qDebug() << resizeEv->size();
}
return QObject::eventFilter(obj, event);
}
main.cpp
#include <QtGui>
#include "filter.hpp"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
ResizeFilter filter;
QWidget window;
window.installEventFilter(&filter);
window.showMaximized();
return app.exec();
}
filter.pro
TEMPLATE = app
HEADERS = filter.hpp
SOURCES = main.cpp filter.cpp
When testing this on my PC it gave the output:
QSize(840, 420)
QSize(1280, 952)

Related

Qt widget does not receive keyPressEvent

My child widget does not get keyPressEvents, while if I put the same widget as top level window, it does. I try to set it get focus, but it has no effect on this. Code is below, showing what I try to get to work.
#include <QApplication>
#include <QKeyEvent>
#include <QLCDNumber>
#include <QLabel>
#include <QVBoxLayout>
class DigitSummer: public QLCDNumber {
Q_OBJECT
public:
DigitSummer(QWidget *parent = nullptr) : QLCDNumber(parent) {
}
protected:
void keyPressEvent(QKeyEvent *event) override {
display(intValue() + event->text().toInt());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#if 1 // this version does not work, number does not increase
QWidget widget;
widget.setLayout(new QVBoxLayout());
widget.layout()->addWidget(new QLabel("Press digits!"));
DigitSummer summer; // in stack: must be after widget to avoid child delete
widget.layout()->addWidget(&summer);
widget.setFocusProxy(&summer); // I notice no effect!
widget.show();
#else // this version works, number grows with keypresseas
DigitSummer summer;
summer.show();
#endif
return a.exec();
}
#include "main.moc"
And for completenes, .pro file for the same:
QT += core gui widgets
TARGET = QtMCVE
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11
QMAKE_CXXFLAGS += -Wall -Wextra
SOURCES += main.cpp
How to fix the widget to receive key events?
This related question suggests installing event filter, but I don't want to do that, there must be a self-contained way to fix the widget itself.
I think you need to set the focus policy for the widget before it will accept keyboard input. In your ctor try...
setFocusPolicy(Qt::StrongFocus);
Having said that, I'm really not sure why the behaviour would differ for top-level and non-top-level widgets.
Working version of the question code:
#include <QApplication>
#include <QKeyEvent>
#include <QLCDNumber>
#include <QLabel>
#include <QVBoxLayout>
class DigitSummer: public QLCDNumber {
Q_OBJECT
public:
DigitSummer(QWidget *parent = nullptr) : QLCDNumber(parent) {
setFocusPolicy(Qt::StrongFocus);
}
protected:
void keyPressEvent(QKeyEvent *event) override {
display(intValue() + event->text().toInt());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget widget;
widget.setLayout(new QVBoxLayout());
widget.layout()->addWidget(new QLabel("Press digits!"));
widget.layout()->addWidget(new DigitSummer);
widget.show();
return a.exec();
}
#include "main.moc"

QQuickWidget grab image

I am saving an image of a QQuickWidget with several QML children but all I have is a blank image.
C++ side:
QQuickWidget* content..
content->setSource(QUrl("qml:/main.qml"));
QPixmap *pm = content->grab(QRect(QPoint(0,0),QSize(-1,-1));
pm->save("someFilename.png", 0, 100);
QML side:
Rectangle{ width: 5; height: 5; color: "yellow"; objectname: "rootobj"}
In the QML I wish to dynamically add children and be able to show them in the image. I have tried QQuickWindow grabWindow method with a connection to a slot and it works but it captures only the window visible area and I need to capture the whole QML.
I believe this is not rocket science just that I am not getting it somewhere. Thanks for your replies!
Addendum:
Ok, I do not think its the issue of before/after rendering since I can see all the qml children before I call the picture grabber. So sorry for not being precise.
c++ side:
QQuickWidget* content..
content->setSource(QUrl("qml:/main.qml"));
//do all my dynamic qml children adding
After I can visually see all my qml:
QPixmap *pm = content->grab(QRect(QPoint(0,0),QSize(-1,-1));
pm->save(....
Unless I am wrong, I dont think its rendering issue. Thank you!
Issue is like Mido said. You can solve it like follows.
Create a class Viewer:
viewer.h
class Viewer : public QQuickView{
Q_OBJECT
public:
explicit Viewer(QWindow *parent = 0);
Viewer(bool showBar);
virtual ~Viewer();
void setMainQmlFile(const QString file);
void addImportPath(const QString path);
public slots:
void beforeRendering();
void afterRendering()
}
Viewer.cpp
#include "viewer.h"
Viewer::Viewer(QWindow *parent)
: QQuickView(parent)
{
setWidth(800);
setHeight(480);
connect(this, SIGNAL(beforeRendering()), this, SLOT(beforeRendering()));
connect(this, SIGNAL(afterRendering()), this, SLOT(afterRendering()));
}
void Viewer::setMainQmlFile(const QString file)
{
setSource(QUrl::fromLocalFile(file));
}
void Viewer::addImportPath(const QString path)
{
engine()->addImportPath(path);
}
void Viewer::beforeRendering()
{
//
}
void Viewer::afterRendering()
{
//grab window
QImage img = this->grabWindow();
img.save(path);
//or your code
}
main.cpp
Viewer *viewer = new Viewer;
//
///
//
viewer->setMainQmlFile(QStringLiteral("qml/main.qml"));
viewer->show();
I think your issue is that the capture screen is done before the rendering of the QML object.
In order to make it work you should connect the grab of the signal after rendering signal:
connect(this, SIGNAL(beforeRendering()), this, SLOT(sltBeforeRendering()));
connect(this, SIGNAL(afterRendering()), this, SLOT(sltAfterRendering()));
do the grab in sltAfterRendering slot.
To grab screen I use the grabWindow() function and I call it from QML.
It depends on the behaviour that you want from your software.
Try this:
grabber.h
#ifndef GRABBER_H
#define GRABBER_H
#include <QObject>
#include <QImage>
#include <QQuickView>
class Grabber : public QObject
{
Q_OBJECT
public:
explicit Grabber(QObject *parent = 0);
Grabber(QQuickView *view);
~Grabber();
Q_INVOKABLE void capture(QString const &path) const;
signals:
public slots:
private:
QQuickView* view_;
};
#endif // GRABBER_H
grabber.cpp
#include "grabber.h"
Grabber::Grabber(QObject *parent) :
QObject(parent)
{
}
Grabber::Grabber(QQuickView* view) :
view_(view)
{
}
Grabber::~Grabber()
{
if(view_ != NULL)
{
delete view_;
view_ = NULL;
}
}
void Grabber::capture(QString const &path) const
{
QImage img = view_->grabWindow();
img.save(path);
}
main.cpp
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QQmlContext>
#include <QQmlEngine>
#include "grabber.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer *viewer = new QtQuick2ApplicationViewer;
Grabber * grab = new Grabber(viewer);
viewer->setHeight(480);
viewer->setWidth(800);
viewer->rootContext()->setContextProperty("grab", grab);
viewer->setMainQmlFile(QStringLiteral("qml/main.qml"));
viewer->showExpanded();
return app.exec();
}
Call it from QML with:
grab.capture(path + "imageName.png")

glewInit with Qt5 returns Missing GL version

I have been trying to use Qt5 to give me an OpenGL context, which I believe it does, but when I try to call glewInit() from within the initializeGL function, the error returns back "Missing GL version," which I have been led to believe indicates that there is no valid context. The solution I saw was to call glewInit() from within initializeGL... but I'm already doing that.
I am setting the clear color and clearing to dark red to verify that gl calls are working, which they appear to be.
Any suggestions?
main.c
#define QT_NO_OPENGL_ES_2
#include <QApplication>
#include "glwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GLWidget w;
w.show();
return a.exec();
}
glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <GL/glew.h>
#define QT_NO_OPENGL_ES_2
#include <QGLWidget>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QGLWidget *parent = 0);
~GLWidget();
QSize minimumSizeHint() const;
QSize sizeHint() const;
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
};
#endif // GLWIDGET_H
glwidget.cpp
#include "glwidget.h"
GLWidget::GLWidget(QGLWidget *parent) :
QGLWidget(parent)
{
}
GLWidget::~GLWidget() {}
QSize GLWidget::minimumSizeHint() const {
return QSize(640, 480);
}
QSize GLWidget::sizeHint() const {
return QSize(800, 600);
}
void GLWidget::initializeGL() {
GLenum err = glewInit();
if (GLEW_OK != err) {
printf("GLEW error: %s\n", glewGetErrorString(err));
} else {
printf("Glew loaded; using version %s\n", glewGetString(GLEW_VERSION));
}
glClearColor(0.2f, 0, 0, 1.0f);
}
void GLWidget::resizeGL(int w, int h) {
}
void GLWidget::paintGL() {
glClear( GL_COLOR_BUFFER_BIT );
}
Something tells me this is because of the QGLWidget's default QGLFormat using OpenGL version 1.0 (Looking through GLEW's change logs, it seems the earliest version they claim to fully support is 1.5) . Try instead to override the QGLWidget constructor that requires a QGLFormat and pass it an instance of QGLFormat that uses the version you are targeting.
The call to your widget should look something like:
QGLFormat format;
format.setVersion(3,3); // or whatever version you are targeting.
format.setDoubleBuffer(true);
GLWidget * widget = new GLWidget(format);

Qt creating children threads using QFuture error

I am trying to make a Collaborative Editor(I have to use Linux networking libraries for all the networking stuff), I have the main widget(custom made class that inherits QWidget) with all the components. In the constructor I create all the Widgets on this main Widget and at the end I try to create a new thread using QFuture(I use QFuture instead of QThread cause it allows me easily to call functions with any type of parameters, like QTextEdit, QTextCursor...) but it gives me this error at compilation:
"QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x1b064b0), parent's thread is QThread(0x1985750), current thread is QThread(0x1ae7610)".
How to solve the error?
Here is my code:
mainwindow.h:
...//includes
using namespace QtConcurrent;
...
namespace Ui {
class Widget;
class TextEdit;
}
class TextEdit;
class Widget;
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
...
QFuture<void> thread;
}
class TextEdit : public QTextEdit {
Q_OBJECT
...
}
static void receiveKeyPress(TextEdit *textedit, QTextCursor *secondUserCursor) {
unsigned long long int Number = NULL;
QMessageBox::information(textedit->parentWidget(), "UI Component", "This makes the thread to throw the error");
while(1) if(connected == 1) {
read(recvFileDescriptor, &Number, sizeof(unsigned long long int));
if( Number != NULL)
if( Number == Qt::Key_Home )
secondUserCursor->movePosition(QTextCursor::StartOfLine);
...
else {
QTextCharFormat backgroundFormat = textedit->textCursor().charFormat();
backgroundFormat.setBackground(QColor("lightGreen"));
//If I don't use QMessageBox up there, it breaks here on the next command
secondUserCursor->setCharFormat(backgroundFormat);
secondUserCursor->setPosition(textedit->textCursor().position());
secondUserCursor->insertText(QString::number(Number));
} //else
}//while
}//the function
And mainwindow.cpp:
#include "mainwindow.h"
Widget::Widget(QWidget *parent) {
...
thread = run(receiveKeyPress, this->edit1, this->edit1->secondUserCursor); //run is from QtConcurrent namespace
}
main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget window;
...
window.show();
return a.exec();
}
I've read here on stackoverflow how others use QObject(which I never used and I don't get the idea of it) and QThread(the only combination) but I already tried to use QThread and I wasn't able to pass QTextEdit and QTextCursor to it.
Thanks in advance
Edit:
mainwindow.h
class TextEdit : public QTextEdit {
Q_OBJECT
...
public slots:
void receiveKeyPress(qulonglong);
...
};
mainwindow.cpp
void TextEdit::receiveKeyPress(qulonglong Number) {
if( Number == Qt::Key_Home )
...
}
recv-thread.h - created based on this link http://developer.qt.nokia.com/doc/qt-4.8/thread-basics.html#example-3-clock
#include <QThread>
#include "mainwindow.h" //To get TextEdit in here
class RecvThread : public QThread {
Q_OBJECT
signals:
void transferDataToSlot(qulonglong Data);
protected:
void run();
};
recv-thread.cpp
#include "recv-thread.h"
void RecvThread::run() {
unsigned long long int Number = NULL;
while(1) if(connected == 1) {
read(recvFileDescriptor, &Number, sizeof(unsigned long long int));
if( Number != NULL) {
emit transferDataToSlot(Number);
}
}
}
main.cpp
...
#include "recv-thread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget window;
RecvThread recvThread;
...
QObject::connect(&recvThread, SIGNAL(transferDataToSlot(qulonglong)), window.edit1, SLOT(receiveKeyPress(qulonglong)), Qt::QueuedConnection); //line 38
recvThread.start();
//Displaying the window
window.show();
a.exec();
recvThread.quit();
recvThread.wait();
return 0;
}
Am I doing it right?

Select a folder or a file

Is there a way in Qt to use just one dialog in order to select either a file or a folder?
What I mean is that I'd like to have an option, let's call it select, and by using this user could, from the same dialog, pick either a folder or a file.
There isn't a built in widget, but it is easy enough to connect a QDirModel to a QTreeView and get the selection signals.
Here is an example to get you started:
test.cpp
#include <QtGui>
#include "print.h"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QDirModel mdl;
QTreeView view;
Print print(&mdl);
view.setModel(&mdl);
QObject::connect(
view.selectionModel(),
SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)),
&print,
SLOT(currentChanged(const QModelIndex&,const QModelIndex&)));
view.show();
return app.exec();
}
print.h
#ifndef _PRINT_H_
#define _PRINT_H_
#include <QtGui>
class Print : public QObject
{
Q_OBJECT
public:
Print(QDirModel* mdl);
~Print();
public slots:
void currentChanged(const QModelIndex& current, const QModelIndex&);
private:
QDirModel* mModel;
Q_DISABLE_COPY(Print)
};
#endif
print.cpp
#include "print.h"
Print::Print(QDirModel* mdl) : QObject(0), mModel(mdl) {}
Print::~Print() {}
void Print::currentChanged(const QModelIndex& current, const QModelIndex&)
{
qDebug() << mModel->filePath(current);
}

Resources