我通过两个函数mousepress event和paintevent画了一条线和一个圆。 我想要类似的想法,例如,当我激活工具栏中的按钮时,我将激活绘制线条的功能,如果单击另一个按钮,我将激活绘制圆圈的功能。
void Label::mousePressEvent(QMouseEvent *pQEvent)
{
if (pQEvent->button() == Qt::LeftButton) {
(firstClick ? start : end) = pQEvent->pos();
if(firstClick = !firstClick)
{
double distance=sqrt(pow(start.x()-end.x(), 2) + pow(start.y()-end.y(), 2));
emit sendCalculDistance(distance);
}
update();
pQEvent->accept();
}
}
void Label::paintEvent(QPaintEvent *pQEvent)
{
QLabel::paintEvent(pQEvent);
if (!firstClick) return;
QPainter painter(this);
QPen pen(Qt::red);
pen.setWidth(4);
painter.setPen(pen);
painter.drawLine(start, end);
}
****************
/* void Label::mousePressEvent(QMouseEvent *pQEvent)
{
if (pQEvent->button() == Qt::LeftButton) {
(firstClick ? center : mouse_pos) = pQEvent->pos();
firstClick = !firstClick;
update();
pQEvent->accept();
}
}
void Label::paintEvent(QPaintEvent *pQEvent)
{
QLabel::paintEvent(pQEvent);
if (!firstClick) return;
int radius = QLineF( center, mouse_pos ).length();
QPainter painter( this );
QPen pen(Qt::red);
pen.setWidth(4);
painter.setPen(pen);
painter.drawEllipse( center, radius, radius );
}
*/
答案 0 :(得分:0)
这是我对SO: update does not call paintEvent?的回答的延续。
因此,我采用了先前的示例代码(仍然放在我的硬盘上)并进行了相应的扩展:
enum PaintMode {
PaintLine, PaintCirc, NPaintModes
};
class MainWindow
中): PaintMode _paintMode;
MainWindow::paintEvent()
的扩展名: switch (_paintMode) {
case PaintLine:
painter.drawLine(_start, _end);
break;
case PaintCirc: {
const int width = std::abs(_end.x() - _start.x());
const int height = std::abs(_end.y() - _start.y());
const int r = std::min(width, height) / 2;
painter.drawEllipse((_start + _end) / 2, r, r);
} break;
}
QToolBar qToolBar;
QActionGroup qTglGrp(&qToolBar);
QAction qTglLine("Line", &qTglGrp);
qTglLine.setCheckable(true);
if (winMain.paintMode() == PaintLine) qTglLine.setChecked(true);
qToolBar.addAction(&qTglLine);
QAction qTglCirc("Circle", &qTglGrp);
qTglCirc.setCheckable(true);
if (winMain.paintMode() == PaintCirc) qTglCirc.setChecked(true);
qToolBar.addAction(&qTglCirc);
winMain.addToolBar(&qToolBar);
QObject::connect(&qTglLine, &QAction::triggered,
[&](bool checked) { if (checked) winMain.setPaintMode(PaintLine); });
QObject::connect(&qTglCirc, &QAction::triggered,
[&](bool checked) { if (checked) winMain.setPaintMode(PaintCirc); });
完整的示例testQMainWindowPaint.cc
:
#include <QtWidgets>
enum PaintMode {
PaintLine, PaintCirc, NPaintModes
};
class MainWindow: public QMainWindow {
private:
QPoint _start, _end;
bool _firstClick;
PaintMode _paintMode;
public:
MainWindow();
virtual ~MainWindow() = default;
MainWindow(const MainWindow&) = delete;
MainWindow& operator=(const MainWindow&) = delete;
PaintMode paintMode() const { return _paintMode; }
void setPaintMode(PaintMode mode);
protected:
virtual void mousePressEvent(QMouseEvent *pQEvent) override;
virtual void paintEvent(QPaintEvent *pQEvent) override;
};
MainWindow::MainWindow():
QMainWindow(),
_start(0, 0), _end(0, 0), _firstClick(true),
_paintMode(PaintLine)
{ }
void MainWindow::setPaintMode(PaintMode mode)
{
_paintMode = mode;
update();
}
void MainWindow::mousePressEvent(QMouseEvent *pQEvent)
{
if (pQEvent->button() == Qt::LeftButton) {
(_firstClick ? _start : _end) = pQEvent->pos();
_firstClick = !_firstClick;
update();
pQEvent->accept();
}
}
void MainWindow::paintEvent(QPaintEvent *pQEvent)
{
QMainWindow::paintEvent(pQEvent);
if (!_firstClick) return;
QPainter painter(this);
QPen pen(Qt::red);
pen.setWidth(4);
painter.setPen(pen);
switch (_paintMode) {
case PaintLine:
painter.drawLine(_start, _end);
break;
case PaintCirc: {
const int width = std::abs(_end.x() - _start.x());
const int height = std::abs(_end.y() - _start.y());
const int r = std::min(width, height) / 2;
painter.drawEllipse((_start + _end) / 2, r, r);
} break;
}
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// init GUI
MainWindow winMain;
QToolBar qToolBar;
QActionGroup qTglGrp(&qToolBar);
QAction qTglLine("Line", &qTglGrp);
qTglLine.setCheckable(true);
if (winMain.paintMode() == PaintLine) qTglLine.setChecked(true);
qToolBar.addAction(&qTglLine);
QAction qTglCirc("Circle", &qTglGrp);
qTglCirc.setCheckable(true);
if (winMain.paintMode() == PaintCirc) qTglCirc.setChecked(true);
qToolBar.addAction(&qTglCirc);
winMain.addToolBar(&qToolBar);
winMain.show();
// install signal handlers
QObject::connect(&qTglLine, &QAction::triggered,
[&](bool checked) { if (checked) winMain.setPaintMode(PaintLine); });
QObject::connect(&qTglCirc, &QAction::triggered,
[&](bool checked) { if (checked) winMain.setPaintMode(PaintCirc); });
// runtime loop
return app.exec();
}
Qt项目文件(未更改)testQMainWindowPaint.pro
:
SOURCES = testQMainWindowPaint.cc
QT += widgets
在Windows 10的cygwin64中进行了编译:
$ qmake-qt5 testQMainWindowPaint.pro
$ make
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQMainWindowPaint.o testQMainWindowPaint.cc
g++ -o testQMainWindowPaint.exe testQMainWindowPaint.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
$ ./testQMainWindowPaint
Qt Version: 5.9.4
在主窗口中单击两次后,我做了一个快照(左图),然后在另一个[kbd] Circle 上单击了(右图):
恕我直言,应用程序现在可以执行OP实际需要的操作:
我想要一些想法,例如,当我激活工具栏中的按钮时,我将激活绘制线条的功能,如果单击另一个按钮,我将激活绘制圆圈的功能。
但是,我有某种感觉,这可能不是预期的。当更改绘制模式时(通过单击工具栏中的),绘制的图元立即更改。取而代之的是,工具栏选择可能会在下一次输入时生效。
在这种情况下,class MainWindow
必须稍作更改:实际绘画需要第二种绘画模式,在下一个交互周期结束之前,第二种绘画模式不会改变:
class MainWindow: public QMainWindow {
private:
QPoint _start, _end;
bool _firstClick;
PaintMode _paintMode, _paintModeEff;
public:
MainWindow();
virtual ~MainWindow() = default;
MainWindow(const MainWindow&) = delete;
MainWindow& operator=(const MainWindow&) = delete;
PaintMode paintMode() const { return _paintMode; }
void setPaintMode(PaintMode mode);
PaintMode effectivePaintMode() const { return _paintModeEff; }
protected:
virtual void mousePressEvent(QMouseEvent *pQEvent) override;
virtual void paintEvent(QPaintEvent *pQEvent) override;
};
MainWindow::MainWindow():
QMainWindow(),
_start(0, 0), _end(0, 0), _firstClick(true),
_paintMode(PaintLine), _paintModeEff(PaintLine)
{ }
void MainWindow::setPaintMode(PaintMode mode)
{
_paintMode = mode;
}
void MainWindow::mousePressEvent(QMouseEvent *pQEvent)
{
if (pQEvent->button() == Qt::LeftButton) {
(_firstClick ? _start : _end) = pQEvent->pos();
_firstClick = !_firstClick;
if (_firstClick) _paintModeEff = _paintMode;
update();
pQEvent->accept();
}
}
void MainWindow::paintEvent(QPaintEvent *pQEvent)
{
QMainWindow::paintEvent(pQEvent);
if (!_firstClick) return;
QPainter painter(this);
QPen pen(Qt::red);
pen.setWidth(4);
painter.setPen(pen);
switch (_paintModeEff) {
case PaintLine:
painter.drawLine(_start, _end);
break;
case PaintCirc: {
const int width = std::abs(_end.x() - _start.x());
const int height = std::abs(_end.y() - _start.y());
const int r = std::min(width, height) / 2;
painter.drawEllipse((_start + _end) / 2, r, r);
} break;
}
}
单击两次(左图)后会出现一条线,更改绘制模式不会立即生效(中间图),但是再次单击两次(右图)时才生效:
样本的另一种修改:
鼠标交互和绘图现在位于从class Canvas
派生的QWidget
中。现在,主窗口是QMainWindow
的实例,但是有一个新实例Canvas canvas
用作QMainWindow winMain
的中央小部件。
#include <QtWidgets>
enum PaintMode {
PaintLine, PaintCirc, NPaintModes
};
class Canvas: public QWidget {
private:
QPoint _start, _end;
bool _firstClick;
PaintMode _paintMode, _paintModeEff;
public:
Canvas();
virtual ~Canvas() = default;
Canvas(const Canvas&) = delete;
Canvas& operator=(const Canvas&) = delete;
PaintMode paintMode() const { return _paintMode; }
void setPaintMode(PaintMode mode);
PaintMode effectivePaintMode() const { return _paintModeEff; }
protected:
virtual void mousePressEvent(QMouseEvent *pQEvent) override;
virtual void paintEvent(QPaintEvent *pQEvent) override;
};
Canvas::Canvas():
QWidget(),
_start(0, 0), _end(0, 0), _firstClick(true),
_paintMode(PaintLine), _paintModeEff(PaintLine)
{ }
void Canvas::setPaintMode(PaintMode mode)
{
_paintMode = mode;
}
void Canvas::mousePressEvent(QMouseEvent *pQEvent)
{
if (pQEvent->button() == Qt::LeftButton) {
(_firstClick ? _start : _end) = pQEvent->pos();
_firstClick = !_firstClick;
if (_firstClick) _paintModeEff = _paintMode;
update();
pQEvent->accept();
}
}
void Canvas::paintEvent(QPaintEvent *pQEvent)
{
QWidget::paintEvent(pQEvent);
if (!_firstClick) return;
QPainter painter(this);
QPen pen(Qt::red);
pen.setWidth(4);
painter.setPen(pen);
switch (_paintModeEff) {
case PaintLine:
painter.drawLine(_start, _end);
break;
case PaintCirc: {
const int width = std::abs(_end.x() - _start.x());
const int height = std::abs(_end.y() - _start.y());
const int r = std::min(width, height) / 2;
painter.drawEllipse((_start + _end) / 2, r, r);
} break;
}
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// init GUI
QMainWindow winMain;
Canvas canvas;
winMain.setCentralWidget(&canvas);
QToolBar qToolBar;
QActionGroup qTglGrp(&qToolBar);
QAction qTglLine("Line", &qTglGrp);
qTglLine.setCheckable(true);
if (canvas.paintMode() == PaintLine) qTglLine.setChecked(true);
qToolBar.addAction(&qTglLine);
QAction qTglCirc("Circle", &qTglGrp);
qTglCirc.setCheckable(true);
if (canvas.paintMode() == PaintCirc) qTglCirc.setChecked(true);
qToolBar.addAction(&qTglCirc);
winMain.addToolBar(&qToolBar);
winMain.show();
// install signal handlers
QObject::connect(&qTglLine, &QAction::triggered,
[&](bool checked) { if (checked) canvas.setPaintMode(PaintLine); });
QObject::connect(&qTglCirc, &QAction::triggered,
[&](bool checked) { if (checked) canvas.setPaintMode(PaintCirc); });
// runtime loop
return app.exec();
}
样本快照: