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"
Related
I have a fully working application that makes use of QGraphicsView + QGLWidget and QGraphicsScene to draw a 3D scene with user interaction.
The concept is explained in the Boxes example from Qt5.
Since updating to Qt 5.12 the application doesn't work anymore. Apart from some other minor issue that I already fixed, now I have everything setup, but the viewport doesn't display anything.
I created a minimum concept program that creates a QGraphicsView, a QGLWidget as a viewport, and a QGraphicsScene derived class that draws the viewport.
I setup everything, but the QGraphicsScene::DrawBackground() function isn't called.
The interesting part is that the application works fine in Qt 5.6 but doesn't in 5.12.
What has changed between the two versions?
Following is the sample app:
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(Prototypes)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets OpenGL)
add_executable(Prototypes main.cpp GraphicsView.cpp GraphicsView.h Scene.cpp Scene.h)
target_link_libraries(Prototypes Qt5::Core Qt5::OpenGL Qt5::Widgets)
main.cpp
#include "GraphicsView.h"
#include "Scene.h"
#include <QApplication>
#include <QGLWidget>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGLWidget *widget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
widget->makeCurrent();
Scene scene(1024,768);
GraphicsView view;
view.setViewport(widget);
view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
view.setScene(&scene);
view.resize(800, 600);
view.show();
return app.exec();
}
Scene.h
#ifndef PROTOTYPES_SCENE_H
#define PROTOTYPES_SCENE_H
#include <QGraphicsScene>
class QTimer;
class Scene : public QGraphicsScene {
Q_OBJECT
public:
Scene(int width, int height);
protected:
QTimer *m_timer;
void drawBackground(QPainter *painter, const QRectF &rect) override;
};
#endif //PROTOTYPES_SCENE_H
Scene.cpp
#include "Scene.h"
#include <QPainter>
#include <QDebug>
#include <QTimer>
Scene::Scene(int width, int height)
{
setSceneRect(0,0,width, height);
//m_timer = new QTimer(this);
//m_timer->setInterval(20);
//connect(m_timer, SIGNAL(timeout()), this, SLOT(update()));
//m_timer->start();
}
void Scene::drawBackground(QPainter *painter, const QRectF &rect)
{
qDebug() << "DrawBackground";
}
GraphicsView.h
#ifndef PROTOTYPES_GRAPHICSVIEW_H
#define PROTOTYPES_GRAPHICSVIEW_H
#include <QGraphicsView>
class GraphicsView : public QGraphicsView {
public:
GraphicsView();
protected:
void resizeEvent(QResizeEvent *event) override;
};
#endif //PROTOTYPES_GRAPHICSVIEW_H
GraphicsView.cpp
#include "GraphicsView.h"
#include <QResizeEvent>
#include <QDebug>
void GraphicsView::resizeEvent(QResizeEvent *event)
{
if (scene()) {
qDebug() << "Set Scene Rect " << event->size();
scene()->setSceneRect(QRect(QPoint(0, 0), event->size()));
}
QGraphicsView::resizeEvent(event);
}
GraphicsView::GraphicsView()
{
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
}
As per the comment, QGLWidget has been marked obsolete for some time and comes with the warning...
This class is obsolete. It is provided to keep old source code
working. We strongly advise against using it in new code.
The solution is to use QOpenGLWidget instead.
I've recently started learning Qt and I'm a beginner of it now. So as first example for myself I wrote the following simple example.
The example is named Calculator. It now only has two buttons an a line edit. It's here:
:
My Calculator.h is this:
#ifndef CALCULATOR_H
#define CALCULATOR_H
#include<QDialog>
#include "ui_Calculator.h"
class Calculator : public QDialog, public Ui::Calculator
{
Q_OBJECT
public:
Calculator(QWidget* parent = 0);
private slots:
void myslot();
};
#endif // CALCULATOR_H
And the Calculator.cpp is this:
#include <QtWidgets>
#include "calculator.h"
Calculator::Calculator(QWidget *parent)
:QDialog(parent)
{
setupUi(this);
connect(oneButton,SIGNAL(clicked(bool)), this, SLOT(myslot()));
}
void Calculator::myslot(){
lineEdit -> setText("1");
}
And this is the main.cpp:
#include <QApplication>
#include <QDialog>
#include "ui_Calculator.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Ui::Calculator ui;
QDialog* dialog = new QDialog;
ui.setupUi(dialog);
dialog -> show();
return app.exec();
}
The program runs fine without any error. But when I click on 1 button, nothing will be printed/shown in the line edit. Why please?
And what part of my program should I change to solve the issue please?
You are setting up the wrong class in your main.
You should use your custom Calculator class and not QDialog.
setupUi only initializes your elements but your code in Calculator never gets called. Your main should look like this:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Calculator calc; //using your Calculator class.
calc.show();
return app.exec();
}
And don't include ui_calculator.h but calculator.h
i am trying to take a feedback data which is published from arduino and subscribed to my GUI created in QT.
Now i have main.cpp and mainwindow.cpp.
main.cpp
#include <QtGui>
#include <ros/ros.h>
#include <QApplication>
#include "../include/abc/main_window.hpp"
#include "std_msgs/String.h"
#include <std_msgs/UInt16.h>
#include <QMainWindow>
#include <std_msgs/Float32.h>
void chatterCallback(const std_msgs::UInt16 &fb_msg){
ROS_INFO("Feedback: [%f]", fb_msg.data);
ui.label_6->setText(QString("%1").arg(fb_msg.data));
}
int main(int argc, char **argv) {
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("feedback",1000, chatterCallback);
ros::spinOnce();
QApplication app(argc, argv);
abc::MainWindow w(argc,argv);
w.show();
w.setWindowTitle("GUI for Controlling Servo Motor");
app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
int result = app.exec();
return result;}
mainwindow.cpp
namespace abc {
using namespace Qt;
QSerialPort *serial;
MainWindow::MainWindow(int argc, char** argv, QWidget *parent)
: QMainWindow(parent)
, qnode(argc,argv)
{
ui.setupUi(this);
}
MainWindow::~MainWindow() {}
void MainWindow::on_horizontalSlider_valueChanged(int value)
{
ui.label_5->setText(QString("%1").arg(value));
msg.data = ui.label_5->text().toUInt();
ROS_INFO("%d", msg.data);
chatter_pub.publish(msg);
ros::spinOnce();
}
main_window.hpp
#ifndef abc_MAIN_WINDOW_H
#define abc_MAIN_WINDOW_H
#include <QtGui/QMainWindow>
#include "ui_main_window.h"
#include "qnode.hpp"
#include <QtSerialPort/QSerialPort>
#include <ros/ros.h>
#include "std_msgs/UInt16.h"
namespace abc {
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(int argc, char** argv, QWidget *parent = 0);
~MainWindow();
public Q_SLOTS:
private:
Ui::MainWindowDesign ui;
ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise <std_msgs::UInt16> ("chatter", 1000);
QSerialPort *arduino;
QNode qnode;
};
} // namespace abc
#endif // abc_MAIN_WINDOW_H
Now when i run this code, it shows me that UI is not declared in main.cpp.
I wanted to display the data from feedback to label_6 (TextBox). The data is only available in main.cpp, any suggestions are highly appreciable.
Thanks in advance.
You will have to pass the fb_msg.data as an argument to the MainWindow constructor. Then you can set the UI element in the MainWindow thread.
Alternatively once you create the MainWindow instance in your main, you can emit a signal which you catch and process in the MainWindow thread.
You cannot modify the UI elements from a different thread.
I have a simple application in Qt that has a QMainWindow and a QWebEngineView that loads an html page. I've set the QApplication name and the QMainWindow title.
app.setApplicationName("FooApp");
window.setWindowTitle("FooApp Window");
When I use a screen reader, it will read the main window title as:
FooApp C:/Users/tulio/Desktop/TestApp//bin/debug/test.exe
I just need it to read the application name, how can I do this?
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
a.setApplicationName("FooApp");
MainWindow w;
w.setWindowTitle("FooApp Window");
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include <QLayout>
#include <QApplication>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) {
this->layout()->addWidget(&web_view_);
this->layout()->setMargin(0);
this->resize(QSize(1000, 700));
QString path = QApplication::applicationDirPath() + "/index.html";
qDebug() << QString("HTML Path %1").arg(path);
web_view_.page()->setUrl(QUrl::fromLocalFile(path));
web_view_.resize(this->size());
channel_.registerObject("Test", &test_);
web_view_.page()->setWebChannel(&channel_);
}
MainWindow::~MainWindow() {
}
void MainWindow::resizeEvent(QResizeEvent *event) {
web_view_.resize(event->size());
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWebEngineView>
#include <QResizeEvent>
#include <QWebChannel>
#include <QDebug>
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent=0) : QObject(parent) {}
virtual ~Test() {}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QWebEngineView web_view_;
QWebChannel channel_;
Test test_;
protected:
void resizeEvent(QResizeEvent *event);
};
#endif // MAINWINDOW_H
teste.pro
QT += core gui webengine webenginewidgets webchannel
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = teste
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
index.html
<!DOCTYPE html>
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
I think you need to use accessibleDescription : QString accessibleName : QString which holds the desciption that gets accessed by assistive technologies.
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);
}