使用QPainter在QWidgets

时间:2017-07-26 06:49:36

标签: c++ qt qt5 qpainter

我正在开发一个应用程序,我需要能够在两个QWidget对象之间画一条线。我已经尝试了很多东西,但是我当前的尝试(我认为是正确的方向,我只是认为我缺少一些东西)是拥有包含小部件(我称之为{{1并保存DrawWidget对象添加到的QGridLayout覆盖QWidget方法并调用paintEvent函数。

我遇到的问题是:

  1. 无论我如何尝试获取小部件的位置,该行的端点始终位于错误的位置
  2. 每当我尝试绘制第二行时,我绘制的第一行都会被删除。
  3. 以下是包含小部件的QPainter::drawLine()函数:

    paintEvent

    我已经尝试了许多不同的方法来获取void paintEvent(QPaintEvent *) { if (!drewSinceUpdate){ drewSinceUpdate = true; QPainter painter(this); painter.setPen(QPen(Qt::black)); painter.drawLine(start->geometry().center(), end->geometry().center()); } } 最后一行中小部件的正确位置,我将发布一些方法(我不记得所有方法):

    paintEvent

    为了让我的问题清楚,这是我正在寻找的一个例子,取自QT Diagram Scene ExampleExample of what I want 但这就是我最终得到的结果:

    What I get 感谢您提供的任何帮助。

    注:

    - painter.drawLine(start->pos(), end->pos()); painter.drawLine(start->mapToGlobal(start->geometry().center()), end->mapToGlobal(end->geometry().center())); painter.drawLine(this->mapToGlobal(start->geometry().center()), this->mapToGlobal(end->geometry().center())); painter.drawLine(start->mapTo(this, start->pos()), end->mapTo(this, end->pos())); painter.drawLine(this->mapFrom(start, start->pos()), this->mapFrom(end, end->pos())); start都是我使用其他方法传入的end个对象

    - 与QWidget相关的层次结构为:

    DrawWidget

    编辑:要制作完整且可验证的示例,以下是相关代码的全部内容。

    MainWindow.cpp:

    QMainWindow
    ->QScrollArea
      ->DrawWidget
        ->QGridLayout
          ->Items       <-- These are the things I want to connect
    

    MainWindow.h

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QHBoxLayout>
    #include <QVBoxLayout>
    #include <QTextEdit>
    #include <QPushButton>
    #include <QScrollBar>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        // Setting up the relevant hierarchy 
        ui->setupUi(this);
        scrollArea = new QScrollArea();
        setCentralWidget(scrollArea);
    
        drawWidget = new DrawWidget();
        gridLayout = new QGridLayout();
        gridLayout->setSpacing(300);
        drawWidget->setLayout(gridLayout);
    
        scrollArea->setWidget(drawWidget);
        scrollArea->setWidgetResizable(true);
    
        AddItemSlot();
    
        QApplication::connect(scrollArea->horizontalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(scrollHorizontal()));
    }
    
    // This is just creating a single one of the example widgets which I want to connect
    QWidget* MainWindow::CreateNewItem(){
        QWidget* itemWidget = new QWidget();
        itemWidget->setStyleSheet("background-color: lightgray");
        QHBoxLayout* singleItemLayout = new QHBoxLayout();
        itemWidget->setLayout(singleItemLayout);
    
        QTextEdit* textEdit = new QTextEdit(std::to_string(counter++).c_str());
        textEdit->setStyleSheet("background-color:white;");
        singleItemLayout->addWidget(textEdit);
    
        QVBoxLayout* rightSidePanel = new QVBoxLayout();
        rightSidePanel->setAlignment(Qt::AlignTop);
    
        QPushButton* button1 = new QPushButton("Top Button");
    
        QApplication::connect(button1, SIGNAL(clicked(bool)), this, SLOT(AddItemSlot()));
    
        rightSidePanel->addWidget(button1);
    
        QWidget* rightPanelWidget = new QWidget();
        rightSidePanel->setMargin(0);
        rightPanelWidget->setLayout(rightSidePanel);
    
        singleItemLayout->addWidget(rightPanelWidget);
    
        itemWidget->setLayout(singleItemLayout);
        itemWidget->setMinimumWidth(400);
        itemWidget->setFixedSize(400,200);
    
        return itemWidget;
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::scrollHorizontal()
    {
        scrollArea->ensureWidgetVisible(noteItems.back());
    }
    
    void MainWindow::AddItemSlot()
    {
        QWidget* w = CreateNewItem();
        gridLayout->addWidget(w,currRow, currCol++);
        if (!noteItems.empty()){
            drawWidget->updateEndpoints(noteItems.back(), w);
        }
        noteItems.push_back(w);
    }
    

    DrawWidget.cpp:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QGridLayout>
    #include <QWidget>
    #include <QMainWindow>
    #include <QScrollArea>
    #include <drawwidget.h>
    #include "drawscrollarea.h"
    #include <vector>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    public slots:
        void scrollHorizontal();
        void AddItemSlot();
    
    private:
        Ui::MainWindow *ui;
        QWidget* CreateNewItem();
        int counter = 0, currCol = 0, currRow = 0;
        std::vector<QWidget*> noteItems;
    
        QScrollArea* scrollArea;
        DrawWidget* drawWidget;
        QGridLayout* gridLayout;
    };
    
    #endif // MAINWINDOW_H
    

    DrawWidget.h

    #include "drawwidget.h"
    #include <QDebug>
    #include <QRect>
    
    DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent)
    {
    
    }
    
    void DrawWidget::paintEvent(QPaintEvent *)
    {
        if (!drewSinceUpdate){
            drewSinceUpdate = true;
            QPainter painter(this);
            painter.setPen(QPen(Qt::black));
    
            for (ConnectedPair pair : items){
                const QWidget* from = pair.from;
                const QWidget* to =pair.to;
    
                QPoint start =  from->mapToGlobal(from->rect().topRight() +  QPoint(0, from->height()/2));
                QPoint end = to->mapToGlobal(to->rect().topLeft() +  QPoint(0, to->height()/2));
    
                painter.drawLine(mapFromGlobal(start), mapFromGlobal(end));
            }
        }
    }
    
    void DrawWidget::updateEndpoints(QWidget* startIn, QWidget* endIn){
        drewSinceUpdate = false;
        items.push_back(ConnectedPair{startIn, endIn});
    }
    

1 个答案:

答案 0 :(得分:3)

对于这种情况,我们使用函数mapToGlobal()mapfromGlobal(),因为pos()返回相对于父级的位置,如果小部件具有不同的父级,这可能会导致问题。

<强> drawwidget.h

#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H

#include <QWidget>

class DrawWidget : public QWidget
{
    Q_OBJECT
public:
    explicit DrawWidget(QWidget *parent = nullptr);

    void addWidgets(const QWidget *from, const QWidget *to);

protected:
    void paintEvent(QPaintEvent *);

private:
    struct WidgetsConnected {
        const QWidget* from;
        const QWidget* to;
    };

    QList<WidgetsConnected> list;

};

#endif // DRAWWIDGET_H

<强> drawwidget.cpp

#include "drawwidget.h"

#include <QPainter>
DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent)
{
}

void DrawWidget::addWidgets(const QWidget * from, const QWidget * to)
{
    list.append(WidgetsConnected{from , to});
    update();
}

void DrawWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    for(const WidgetsConnected el: list){
        const QWidget* from = el.from;
        const QWidget* to = el.to;

        QPoint start =  from->mapToGlobal(from->rect().topRight() +  QPoint(0, from->height()/2));
        QPoint end = to->mapToGlobal(to->rect().topLeft() +  QPoint(0, to->height()/2));

        painter.drawLine(mapFromGlobal(start), mapFromGlobal(end));
    }
}

可以找到完整的示例here

enter image description here

相关问题