Qt events or repaint() function not working - c++

The key event listener or the function repaint() are not working, I've tried calling paintEvent(QPaintEvent *) directly but it didn't work either, thanks to further answers.
Here's the code:
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QRectF>
namespace Ui {
class Window;
}
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
~Window();
void paintEvent(QPaintEvent *);
void keyPressEvent(QKeyEvent * );
private:
Ui::Window *ui;
QRectF player;
QPainter * painter = new QPainter(this);
};
#endif // WINDOW_H
window.cpp
#include "window.h"
#include "ui_window.h"
Window::Window(QWidget *parent) :
QWidget(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
player.setX(0);
player.setY(0);
player.setWidth(50);
player.setHeight(50);
}
Window::~Window()
{
delete ui;
}
void Window::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setPen(QPen(Qt::black, 3, Qt::DashDotLine, Qt::RoundCap));
painter.setBrush(QBrush(Qt::blue));
painter.setRenderHint(QPainter::Antialiasing, true);
painter.drawEllipse(player.x(), player.y(), player.width(), player.height());
}
void Window::keyPressEvent(QKeyEvent * event)
{
if(event->type() == Qt::Key_W)
player.setY(player.y() - 1);
if(event->type() == Qt::Key_S)
player.setY(player.y() + 1);
if(event->type() == Qt::Key_A)
player.setX(player.x() - 1);
if(event->type() == Qt::Key_D)
player.setX(player.x() + 1);
repaint();
}
main.cpp
#include "window.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}

In Window::keyPressEvent, replace event->type() with event->key() everywhere.
Also, take a look at the compiler output. I think it should have warned you about comparing QEvent::Type with Qt::Key objects.

Related

Segfault on clicking on QFrame

This topic might be little lengthy since I have to explain the premise before procceding with the probleme at hand.Firstly my main goal is to have this application in which the user is capable of drag-n-dropping commands from a toolbar in order to form workflows which are send and executed on a remote server.Currently i am working on the client part in qt and it is driving me nuts.
This is my code:
draglabel.h
#ifndef DRAGLABEL_H
#define DRAGLABEL_H
#include <QLabel>
class QDragEnterEvent;
class QDragMoveEvent;
class QFrame;
class DragLabel : public QLabel
{
public:
DragLabel(const QString &text, QWidget *parent);
QString labelText() const;
private:
QString m_labelText;
};
#endif // DRAGLABEL_H
draglabel.c
#include "draglabel.h"
#include <QtWidgets>
DragLabel::DragLabel(const QString &text, QWidget *parent)
: QLabel(parent)
{
QFontMetrics metric(font());
QSize size = metric.size(Qt::TextSingleLine, text);
QImage image(size.width() + 12, size.height() + 12, QImage::Format_ARGB32_Premultiplied);
image.fill(qRgba(0, 0, 0, 0));
QFont font;
font.setStyleStrategy(QFont::ForceOutline);
QLinearGradient gradient(0, 0, 0, image.height()-1);
gradient.setColorAt(0.0, Qt::white);
gradient.setColorAt(0.2, QColor(200, 200, 255));
gradient.setColorAt(0.8, QColor(200, 200, 255));
gradient.setColorAt(1.0, QColor(127, 127, 200));
QPainter painter;
painter.begin(&image);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(gradient);
painter.drawRoundedRect(QRectF(0.5, 0.5, image.width()-1, image.height()-1),
25, 25, Qt::RelativeSize);
painter.setFont(font);
painter.setBrush(Qt::black);
painter.drawText(QRect(QPoint(6, 6), size), Qt::AlignCenter, text);
painter.end();
setPixmap(QPixmap::fromImage(image));
m_labelText = text;
}
QString DragLabel::labelText() const
{
return m_labelText;
}
dragwidget.h
#ifndef DRAGWIDGET_H
#define DRAGWIDGET_H
#include <QWidget>
#include <QFrame>
#include <vector>
#include <set>
#include "draglabel.h"
using namespace std;
class QDragEnterEvent;
class QDropEvent;
class DragWidget : public QFrame
{
public:
DragWidget(QWidget *parent = nullptr);
void setMode(int desiredMode);
void changePairingMode();
void showAvailableCommands();
void initDrawingLayout();
vector<tuple<QString,QString>> actCommands;
vector<tuple<QString,QString>> execCommands;
vector<pair<int,int>>waitingForPair;
int pairingMode=0;
QFrame*drawingCon;
private:
int widgetMode=1;
protected:
void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE;
void dragMoveEvent(QDragMoveEvent *event) Q_DECL_OVERRIDE;
void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
};
#endif // DRAGWIDGET_H
dragwidget.cpp
#include "draglabel.h"
#include "dragwidget.h"
#include "arrowhead.h"
#include <QtWidgets>
#include <QWidget>
#include <QFrame>
#include <QColor>
#include <tuple>
using namespace std;
static inline QString dndProcMimeType() { return QStringLiteral("application/x-fridgemagnet"); }
DragWidget::DragWidget(QWidget *parent)
: QFrame(parent)
{
drawingCon=new QFrame(this);
QPalette newPalette = palette();
newPalette.setColor(QPalette::Window, Qt::white);
setPalette(newPalette);
setWindowTitle(tr("Drag-and-Drop"));
setMinimumSize(300,300);
setAcceptDrops(true);
setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
drawingCon->setPalette(newPalette);
drawingCon->setWindowTitle(tr("Drag-and-Drop"));
drawingCon->setMinimumSize(350,350);
drawingCon->setAcceptDrops(false);
drawingCon->show();
}
void DragWidget::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat(dndProcMimeType())) {
if (children().contains(event->source())) {
event->setDropAction(Qt::MoveAction);
event->accept();
} else {
event->acceptProposedAction();
}
} else if (event->mimeData()->hasText()) {
event->acceptProposedAction();
} else {
event->ignore();
}
}
void DragWidget::dragMoveEvent(QDragMoveEvent *event)
{
if (event->mimeData()->hasFormat(dndProcMimeType())) {
if (children().contains(event->source())) {
if(widgetMode==1)
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
else {
event->ignore();
}
} else {
if(widgetMode==1)
{
event->acceptProposedAction();
}
else
{
if(widgetMode==1)
{
event->accept();
}
else {
event->ignore();
}
}
}
} else if (event->mimeData()->hasText()) {
event->acceptProposedAction();
} else {
event->ignore();
}
}
void DragWidget::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasFormat(dndProcMimeType())) {
const QMimeData *mime = event->mimeData();
QByteArray itemData = mime->data(dndProcMimeType());
QDataStream dataStream(&itemData, QIODevice::ReadOnly);
QString text;
QPoint offset;
dataStream >> text >> offset;
DragLabel *newLabel = new DragLabel(text, this);
newLabel->move(event->pos() - offset);
newLabel->show();
newLabel->setAttribute(Qt::WA_DeleteOnClose);
if (event->source() == this) {
event->setDropAction(Qt::MoveAction);
event->accept();
} else {
tuple<QString,QString> addTest;
addTest=make_tuple(text,"");
actCommands.push_back(make_tuple(text,""));
for(auto it:actCommands)
qDebug()<<get<0>(it)<<" "<<get<1>(it);
event->acceptProposedAction();
}
} else {if (event->mimeData()->hasText()) {
if(widgetMode==1)
{
event->accept();
}
else {
event->ignore();
}
event->acceptProposedAction();
}
}
}
void DragWidget::mousePressEvent(QMouseEvent *event)
{
DragLabel *child = static_cast<DragLabel*>(childAt(event->pos()));
if(!pairingMode){
if (!child)
return;
QPoint hotSpot = event->pos() - child->pos();
if(widgetMode==1)
qDebug()<<child->labelText();
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
dataStream << child->labelText() << QPoint(hotSpot);
QMimeData *mimeData = new QMimeData;
mimeData->setData(dndProcMimeType(), itemData);
mimeData->setText(child->labelText());
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setPixmap(*child->pixmap());
drag->setHotSpot(hotSpot);
child->hide();
if (drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction) == Qt::MoveAction)
child->close();
else {
child->show();
}
}
else {
if(widgetMode==1)
{
DragLabel *child = static_cast<DragLabel*>(childAt(event->pos()));
if (!child)
return;
qDebug()<<"Facem pair cu:"<<child->labelText();
waitingForPair.push_back(make_pair(child->x(),child->y()));
if(waitingForPair.size()==2) {
ArrowHead *line=new ArrowHead(waitingForPair.at(0).first,waitingForPair.at(0).second,waitingForPair.at(1).first,waitingForPair.at(1).second,drawingCon);
line->show();
waitingForPair.erase(waitingForPair.begin(),waitingForPair.begin()+1);
qDebug()<<"Tragem linie";
}
}
}
}
void DragWidget::setMode(int desiredMode)
{
widgetMode=desiredMode;
}
void DragWidget::showAvailableCommands()
{
DragLabel*grep=new DragLabel("grep",this);
grep->move(this->x(),this->y());
grep->show();
DragLabel*cat=new DragLabel("cat",this);
grep->move(this->x()+40,this->y());
cat->show();
DragLabel*wc=new DragLabel("wc",this);
wc->move(this->x()+90,this->y());
wc->show();
}
void DragWidget::changePairingMode()
{
if(pairingMode==1)
pairingMode=0;
else {
pairingMode=1;
}
}
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QTextEdit>
#include "dragwidget.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
protected:
virtual void closeEvent(QCloseEvent *event) override;
private slots:
void handleButton();
void closeAppButton();
void pairButton();
private:
QPushButton *executeCode;
QPushButton *pairCommands;
QPushButton *closeApp;
QTextEdit *inputUser;
QTextEdit *outputServer;
DragWidget * commandLayout=new DragWidget();
DragWidget * availableLayout=new DragWidget();
};
#endif // MAINWINDOW_H
mainWindow.cpp
#include "mainwindow.h"
#include "draglabel.h"
#include "dragwidget.h"
#include <QCoreApplication>
#include <QApplication>
#include <QHBoxLayout>
#include <QPushButton>
#include <QCloseEvent>
#include <QTextEdit>
#include <QFrame>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
executeCode=new QPushButton("Execute");
closeApp=new QPushButton("Close");
pairCommands=new QPushButton("Pair");
connect(closeApp, SIGNAL (released()), this, SLOT (closeAppButton()));
connect(pairCommands, SIGNAL (released()), this, SLOT (pairButton()));
void pairButton();
QHBoxLayout * horizontalLayout=new QHBoxLayout();
commandLayout->setMode(1);
availableLayout->setMode(2);
horizontalLayout->addWidget(commandLayout);
horizontalLayout->addWidget(availableLayout);
availableLayout->showAvailableCommands();
QVBoxLayout*inputBoxes=new QVBoxLayout();
inputUser=new QTextEdit();
outputServer=new QTextEdit();
inputBoxes->addWidget(inputUser);
inputBoxes->addWidget(outputServer);
horizontalLayout->addLayout(inputBoxes);
QVBoxLayout*withButtons=new QVBoxLayout();
withButtons->addLayout(horizontalLayout);
withButtons->addWidget(pairCommands);
withButtons->addWidget(executeCode);
withButtons->addWidget(closeApp);
withButtons->addWidget(new QFrame());
setCentralWidget(new QWidget);
centralWidget()->setLayout(withButtons);
}
void MainWindow::handleButton()
{
}
void MainWindow::closeEvent(QCloseEvent *event)
{
event->accept();
}
void MainWindow::closeAppButton()
{
exit(EXIT_SUCCESS);
}
void MainWindow::pairButton()
{
commandLayout->changePairingMode();
qDebug()<<commandLayout->pairingMode;
}
Note:It might seem idiotic but i have the same class for the "toolbar",from where you're supposed to drag commands and also for part where you are supposed to drag commands and pair them.
This is mostly modified code of the fridge-magnets example on the qt website.
The problem that is giving headaches is drawing lines between dragwidget, I have tried drawing everything in the same QFrame but that proved to be disastrous since the whole pixelMap of the instance dragWidget is overwritten at every draw.The solution with which i came up is to overlay a supplimentary QFrame over my dragWidget in order to draw lines there and everyone to be happy,but as always misfortune strikes at every step.When i am trying to click on the command widget everything's fine but clicking on anything other than a DragLabel results in a segfault due to clicking on the QFrame due to childAt() returning the address of the QFrame overlayed on the first instance of dragWdiget();
My main question is: How can i overcome this obstacle
You should use qobject_cast instead of static_cast.
Add Q_OBJECT macro in each class declaration:
class DragLabel : public QLabel
{
Q_OBJECT
public:
//... class declaration ...
}
class DragWidget : public QFrame
{
Q_OBJECT
public:
//... class declaration ...
}
Then use qobject_cast instead of static_cast for childAt(), for example :
DragLabel *child = qobject_cast<DragLabel*>(childAt(event->pos()));
if(!child){
....
}

Designing a Qt Creator's SideBar in C++

I have created a class for making a sidebar just like in Qt Creator (one to the left). I am having no idea now to make it look exactly like the one in Qt creator as mine looks ugly!
The sidebar.h:
#ifndef _SIDEBAR_H_
#define _SIDEBAR_H_
#include <QVector>
#include <QString>
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <QPixmap>
#include <iostream>
class SideBar : public QWidget
{
public:
SideBar(QWidget *parent=nullptr);
void addIcon(const char *name);
void addIcon(QString &name);
private:
QVBoxLayout *_layout;
};
#endif // SIDEBAR_H
The sidebar.cpp
#include "sidebar.h"
#include <QPushButton>
#include <QIcon>
SideBar::SideBar(QWidget *parent) : QWidget(parent)
{
_layout = new QVBoxLayout(this);
setLayout(_layout);
}
void SideBar::addIcon(const char *name)
{
QString str(name);
addIcon(str);
}
void SideBar::addIcon(QString &file)
{
QPushButton *button = new QPushButton(this);
QPixmap pixmap(file);
QIcon buttonIcon(pixmap);
button->setIcon(buttonIcon);
// button->setIconSize(pixmap.rect().size());
_layout->addWidget(button);
}
This is one i want:
And this is one i got:
A possible solution is to use QAction to handle the clicks and icons, overwriting the methods paintEvent, mousePressEvent, mouseMoveEvent, leaveEvent, changing the colors regarding the state in which the widget is.
sidebar.h
#ifndef SIDEBAR_H
#define SIDEBAR_H
#include <QAction>
#include <QWidget>
class SideBar : public QWidget
{
Q_OBJECT
public:
explicit SideBar(QWidget *parent = nullptr);
void addAction(QAction *action);
QAction *addAction(const QString &text, const QIcon &icon = QIcon());
QSize minimumSizeHint() const;
signals:
public slots:
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void leaveEvent(QEvent * event);
QAction *actionAt(const QPoint &at);
private:
QList<QAction *> mActions;
QAction *mCheckedAction;
QAction *mOverAction;
};
#endif // SIDEBAR_H
sidebar.cpp
#include "sidebar.h"
#include <QPaintEvent>
#include <QPainter>
#include <QDebug>
#include <QEvent>
#define action_height 90
SideBar::SideBar(QWidget *parent) :
QWidget(parent), mCheckedAction(NULL), mOverAction(NULL)
{
setMouseTracking(true);
}
void SideBar::paintEvent(QPaintEvent *event)
{
QPainter p(this);
QFont fontText(p.font());
fontText.setFamily("Helvetica Neue");
p.setFont(fontText);
int action_y = 0;
p.fillRect(rect(), QColor(100, 100, 100));
for(auto action: mActions)
{
QRect actionRect(0, action_y, event->rect().width(), action_height);
if(action->isChecked())
{
p.fillRect(actionRect, QColor(35, 35, 35));
}
if(action == mOverAction){
p.fillRect(actionRect, QColor(150, 150, 150));
}
p.setPen(QColor(255, 255, 255));
QSize size = p.fontMetrics().size(Qt::TextSingleLine, action->text());
QRect actionTextRect(QPoint(actionRect.width()/2 - size.width()/2, actionRect.bottom()-size.height()-5), size);
p.drawText(actionTextRect, Qt::AlignCenter, action->text());
QRect actionIconRect(0, action_y + 10, actionRect.width(), actionRect.height()-2*actionTextRect.height()-10);
QIcon actionIcon(action->icon());
actionIcon.paint(&p, actionIconRect);
action_y += actionRect.height();
}
}
QSize SideBar::minimumSizeHint() const
{
return action_height*QSize(1, mActions.size());
}
void SideBar::addAction(QAction *action)
{
mActions.push_back(action);
action->setCheckable(true);
update();
}
QAction *SideBar::addAction(const QString &text, const QIcon &icon)
{
QAction *action = new QAction(icon, text, this);
action->setCheckable(true);
mActions.push_back(action);
update();
return action;
}
void SideBar::mousePressEvent(QMouseEvent *event)
{
QAction* tempAction = actionAt(event->pos());
if(tempAction == NULL || tempAction->isChecked())
return;
qDebug()<<"clicked";
if(mCheckedAction)
mCheckedAction->setChecked(false);
if(mOverAction == tempAction)
mOverAction = NULL;
mCheckedAction = tempAction;
tempAction->setChecked(true);
update();
QWidget::mousePressEvent(event);
}
void SideBar::mouseMoveEvent(QMouseEvent *event)
{
QAction* tempAction = actionAt(event->pos());
if(tempAction == NULL){
mOverAction = NULL;
update();
return;
}
if(tempAction->isChecked() || mOverAction == tempAction)
return;
mOverAction = tempAction;
update();
QWidget::mouseMoveEvent(event);
}
void SideBar::leaveEvent(QEvent * event)
{
mOverAction = NULL;
update();
QWidget::leaveEvent(event);
}
QAction* SideBar::actionAt(const QPoint &at)
{
int action_y = 0;
for(auto action: mActions)
{
QRect actionRect(0, action_y, rect().width(), action_height);
if(actionRect.contains(at))
return action;
action_y += actionRect.height();
}
return NULL;
}
#undef action_height
The sample code is here.
Screenshots:

QOpenGLWidget problems under Fullscreen

I'm using Qt 5.4.0.
I added two widgets in QMainWindow: QOpenGLWidget and QQuickView. But my problem is when I clicked on fullscreen button, QQuickView would be disappeared and then when I maximized it, QQuickView would be appeared on the screen. what did i do wrong?
my code:
helper.h
#include <QBrush>
#include <QFont>
#include <QPen>
#include <QWidget>
class Helper
{
public:
Helper();
public:
void paint(QPainter *painter, QPaintEvent *event, int elapsed);
private:
QBrush background;
QBrush circleBrush;
QFont textFont;
QPen circlePen;
QPen textPen;
};
helper.cpp
#include <QPainter>
#include <QPaintEvent>
#include <QWidget>
Helper::Helper()
{
QLinearGradient gradient(QPointF(50, -20), QPointF(80, 20));
gradient.setColorAt(0.0, Qt::white);
gradient.setColorAt(1.0, QColor(0xa6, 0xce, 0x39));
background = QBrush(QColor(64, 32, 64));
circleBrush = QBrush(gradient);
circlePen = QPen(Qt::black);
circlePen.setWidth(1);
textPen = QPen(Qt::white);
textFont.setPixelSize(50);
}
void Helper::paint(QPainter *painter, QPaintEvent *event, int elapsed)
{
painter->fillRect(event->rect(), background);
painter->translate(100, 100);
painter->save();
painter->setBrush(circleBrush);
painter->setPen(circlePen);
painter->rotate(elapsed * 0.030);
qreal r = elapsed / 1000.0;
int n = 30;
for (int i = 0; i < n; ++i) {
painter->rotate(30);
qreal factor = (i + r) / n;
qreal radius = 0 + 120.0 * factor;
qreal circleRadius = 1 + factor * 20;
painter->drawEllipse(QRectF(radius, -circleRadius,
circleRadius * 2, circleRadius * 2));
}
painter->restore();
painter->setPen(textPen);
painter->setFont(textFont);
painter->drawText(QRect(-50, -50, 100, 100), Qt::AlignCenter, QStringLiteral("Qt"));
}
glwidget.h
#include <QOpenGLWidget>
class Helper;
class GLWidget : public QOpenGLWidget
{
Q_OBJECT
public:
GLWidget(Helper *helper, QWidget *parent);
public slots:
void animate();
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
private:
Helper *helper;
int elapsed;
};
glwidget.cpp
#include "glwidget.h"
#include "helper.h"
#include <QPainter>
#include <QTimer>
GLWidget::GLWidget(Helper *helper, QWidget *parent)
: QOpenGLWidget(parent), helper(helper)
{
elapsed = 0;
setFixedSize(200, 200);
setAutoFillBackground(false);
}
void GLWidget::animate()
{
elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
update();
}
void GLWidget::paintEvent(QPaintEvent *event)
{
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
helper->paint(&painter, event, elapsed);
painter.end();
}
mainwindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
bool _showFullScreen;
Helper helper;
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QQuickView>
#include <QQuickItem>
#include <QTimer>
#include "glwidget.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
_showFullScreen = false;
QQuickView *view = new QQuickView();
QWidget *container = QWidget::createWindowContainer(view, this);
container->setMinimumSize(200, 200);
container->setMaximumSize(200, 200);
container->setFocusPolicy(Qt::TabFocus);
view->setSource(QUrl("QquickView.qml"));
ui->verticalLayout->addWidget(container);
GLWidget *openGL = new GLWidget(&helper, this);
ui->verticalLayout_2->addWidget(openGL);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), openGL, SLOT(animate()));
timer->start(50);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
if (_showFullScreen == false) {
showFullScreen();
_showFullScreen = true;
} else {
showMaximized();
_showFullScreen = false;
}
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

QPainter black trace when moving QWidget

I created a small test application with 2 widgets, one inside the other.
I reimplemented the mouse move, press and release events for the inner widget in order to be able to move it inside its bigger parent with drag&drop.
However, when I move it a black trace appears from top and from left. This is how it looks:
Here is my code:
main.cpp:
#include <QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPaintEvent>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void paintEvent(QPaintEvent *e);
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include "innerwidget.h"
#include <QPainter>
Widget::Widget(QWidget *parent) :
QWidget(parent)
{
new InnerWidget(this);
resize(400, 200);
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent* e)
{
QPainter p(this);
p.setBrush(Qt::lightGray);
p.drawRect(e->rect());
}
innerwidget.h:
#ifndef INNERWIDGET_H
#define INNERWIDGET_H
#include <QWidget>
#include <QPaintEvent>
class InnerWidget : public QWidget
{
Q_OBJECT
public:
explicit InnerWidget(QWidget *parent = 0);
~InnerWidget();
protected:
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void paintEvent(QPaintEvent *e);
private:
bool m_leftButtonPressed;
QPoint m_mousePosOnBar;
};
#endif // INNERWIDGET_H
innerwidget.cpp:
#include "innerwidget.h"
#include <QPainter>
#include <QPaintEvent>
#include <QStyleOption>
InnerWidget::InnerWidget(QWidget *parent) : QWidget(parent)
{
setGeometry(10, 10, 100, 100);
setStyleSheet("background-color: red");
}
InnerWidget::~InnerWidget()
{
}
void InnerWidget::mousePressEvent(QMouseEvent* e)
{
if(e->button() == Qt::LeftButton)
{
m_mousePosOnBar = e->pos();
m_leftButtonPressed = true;
}
e->accept();
}
void InnerWidget::mouseReleaseEvent(QMouseEvent* e)
{
if(e->button() == Qt::LeftButton)
{
m_leftButtonPressed = false;
}
e->accept();
}
void InnerWidget::mouseMoveEvent(QMouseEvent* e)
{
if(m_leftButtonPressed)
{
move(e->pos().x() - m_mousePosOnBar.x() + geometry().x(),
e->pos().y() - m_mousePosOnBar.y() + geometry().y());
}
e->accept();
}
void InnerWidget::paintEvent(QPaintEvent* e)
{
Q_UNUSED(e)
QPainter p(this);
QStyleOption opt;
opt.init(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
EDIT:
The trace disappears when I call Widget::repaint but then I would have to install an event filter on InnerWidget and repaint everytime it moves. I would want a cleaner solution without having to use event filters...
Can anyone tell me what is really happening?
Calling QWidget::update() in Widget::paintEvent solved the problem:
void Widget::paintEvent(QPaintEvent* e)
{
QPainter p(this);
p.setBrush(Qt::lightGray);
p.drawRect(e->rect());
update();
}

Cancel a cell value in a QTableView

How can I delete a value from a cell in a QTableView?
I created a QTableView but if I press the cancel button of the keyboard on the selected cell nothing happens.
If I want to delete that value I have to double-click the cell and press cancel but I want to delete the value without the double-click, just selecting the cell and press Canc.
Is keyEvent->key() useful?
#Chernobyl
MAINWINDOW.H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QKeyEvent>
#include <QTableView>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) ;
~MainWindow();
QTableView *griglia;
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
MAINWINDOW.CPP
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
qApp->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == griglia && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Cancel)
{
QModelIndex in =griglia->currentIndex();
griglia->model()->setData(in," ");
}
}
return QObject::eventFilter(obj, event);
}
MainWindow::~MainWindow()
{
delete ui;
}
MAIN.CPP
#include "mainwindow.h"
#include "itemdelegate.h"
#include "mymodel.h"
#include <QApplication>
#include <QtGui>
#include <QtCore>
#include <QtWidgets>
#include <QFile>
#include <QString>
#include <QTextStream>
#include <QIdentityProxyModel>
#include <QRegExpValidator>
#define GRIGLIA_RX "^[F0-9]|1[0-9]|2[0-4]$"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFile styleFile( "style.qss" );
styleFile.open( QFile::ReadOnly );
QString style( styleFile.readAll() );
a.setStyleSheet( style );
QWidget *mainWindow = new QWidget;
QStandardItemModel *model = new QStandardItemModel(48,33);
QTableView *griglia = new QTableView;
griglia->setModel(model);
QPushButton *calcola = new QPushButton;
calcola->setText("CALCOLA");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(griglia);
layout->addWidget(calcola);
mainWindow->setLayout(layout);
ItemDelegate *itDelegate = new ItemDelegate;
griglia->setItemDelegate(itDelegate);
mainWindow->showMaximized();
return a.exec();
}
I added QDebug line but if I press Canc no message appears
Use next event filter as in my example or reimplement keyPressEvent:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->tableView && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Shift)
{
qDebug() << "works";
QModelIndex in = ui->tableView->currentIndex();
ui->tableView->model()->setData(in,"");
//ui->tableView->model()->setData(ui->tableView->currentIndex(),""); //or just this
}
}
return QObject::eventFilter(obj, event);
}
To use eventFilter you should also:
protected:
bool eventFilter(QObject *obj, QEvent *event);//in header
and
qApp->installEventFilter(this);//in constructor
You can use Qt::Key_Shift or Qt::Key_Cancel or something else.
EDIT
MAINWINDOW.H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QKeyEvent>
#include <QTableView>
#include "itemdelegate.h"
#include "mymodel.h"
#include <QApplication>
#include <QtGui>
#include <QtCore>
#include <QtWidgets>
#include <QFile>
#include <QString>
#include <QTextStream>
#include <QIdentityProxyModel>
#include <QRegExpValidator>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) ;
~MainWindow();
QTableView *griglia;
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
MAINWINDOW.CPP
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
QWidget *mainWindow = new QWidget;
QStandardItemModel *model = new QStandardItemModel(48,33);
griglia = new QTableView;
griglia->setModel(model);
QPushButton *calcola = new QPushButton;
calcola->setText("CALCOLA");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(griglia);
layout->addWidget(calcola);
mainWindow->setLayout(layout);
ItemDelegate *itDelegate = new ItemDelegate;
griglia->setItemDelegate(itDelegate);
this->setCentralWidget(mainWindow);
qApp->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == griglia && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Cancel)
{
QModelIndex in =griglia->currentIndex();
griglia->model()->setData(in," ");
}
}
return QObject::eventFilter(obj, event);
}
MainWindow::~MainWindow()
{
delete ui;
}
MAIN.CPP
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFile styleFile( "style.qss" );
styleFile.open( QFile::ReadOnly );
QString style( styleFile.readAll() );
a.setStyleSheet( style );
MainWindow my;
my.showMaximized();
return a.exec();
}
Now you should see "works" and cell should be cleared, another code optimization do by yourself.
Addition for multiple selection:
if(obj == ui->tableView && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Shift)
{
qDebug() << "Up";
//ui->tableView->model()->setData(ui->tableView->currentIndex(),"");
QList<QModelIndex> index = ui->tableView->selectionModel()->selectedIndexes();
for(int i = 0; i < index.size(); i++)
ui->tableView->model()->setData(index.at(i),"");
}
}