使用 Qt 库在图形编辑器中选择画布上的特定形状时出现问题

问题描述 投票:0回答:1

我正在编写一个图形编辑器程序。在程序中,我只能绘制两种形状:圆形和矩形。我能够正确选择并拖动矩形,但对于圆形,情况并非如此。如果我的鼠标位于圆圈的左上角及上方,我只能选择并拖动圆圈。

我试图找到contains方法中的逻辑错误,但没有成功。 这是代码:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <memory>
#include <QWidget>
#include <QApplication>
#include <QSizePolicy>
#include <QPainter>
#include <QMouseEvent>
#include <QObject>
#include <QBoxLayout>
#include <QColor>
#include <QPushButton>
class QShapeCanvas;
class shape {
public:
    virtual ~shape() = default;

    virtual void paint(QPainter& canvas) const = 0;

    [[nodiscard]] virtual bool contains(int x, int y) const = 0;

    void move(int dx, int dy) {
        m_x += dx;
        m_y += dy;
    }

    explicit operator std::string() const {
        std::ostringstream oss;
        to_string(oss);
        return oss.str();
    }

    void select() {
        is_selected = true;
    }

    void unselect() {
        is_selected = false;
    }
    [[nodiscard]] int get_x() const{
        return m_x;
    }
    [[nodiscard]] int get_y() const{
        return m_y;
    }
    void set_x(int x){
         m_x = x;
    }
    void set_y(int y){
         m_y = y;
    }

protected:
    int m_x, m_y;

    bool is_selected;

    shape(int x, int y):
        m_x{x},
        m_y{y},
        is_selected{false}{}


    virtual void to_string(std::ostringstream &oss) const = 0;

};

class rectangle : public shape {
public:
    rectangle(int x, int y, int width, int height): shape(x, y),
                                                    m_width{width}, m_height{height} { }

    void paint(QPainter& painter) const override {
        painter.setBrush(QColor(255, 0, 255));
        is_selected ? painter.setPen(QColor(255, 0, 0)) : painter.setPen(Qt::NoPen);
        painter.drawRect(m_x, m_y, m_width, m_height);
    }

    [[nodiscard]] bool contains(int x, int y) const override {
        return x >= m_x && x < (m_x + m_width) &&
               y >= m_y && y < (m_y + m_height);
    }

protected:
    void to_string(std::ostringstream &oss) const override {
        oss << "{ \"name\": \"rectangle\", \"x\": " << m_x << ", \"y\": " << m_y << ", \"width\": " << m_width << ", \"height\": " << m_height << " }";
    }

private:
    int m_width, m_height;
};

class circle : public shape {
public:
    circle(int x, int y, int radius): shape(x, y),
                                      m_radius{radius} { }

    void paint(QPainter& painter) const override {
        painter.setBrush(QColor(255, 255, 0));
        is_selected ? painter.setPen(QColor(255, 0, 0)) : painter.setPen(Qt::NoPen);
        painter.drawEllipse(m_x, m_y, 2*m_radius, 2*m_radius);
    }

    [[nodiscard]] bool contains(int x, int y) const override {
        int dx = x - m_x;
        int dy = y - m_y;
        return (dx * dx + dy * dy) <= (m_radius * m_radius);
    }

protected:
    void to_string(std::ostringstream &oss) const override {
        oss << "{ \"name\": \"circle\", \"x\": " << m_x << ", \"y\": " << m_y << ", \"radius\": " << m_radius << " }";
    }

private:
    const int m_radius;
};

class QShapeCanvas : public QWidget {
public:
    enum ShapesToDraw {
        CircleShape,
        RectangleShape,
        NoneShape
    };

    explicit QShapeCanvas(QWidget* parent = nullptr): QWidget(parent) {
        setMinimumSize(200,200);
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        setFocusPolicy(Qt::StrongFocus);
        next_shape_to_draw = NoneShape;
        selected_shape = nullptr;
        is_in_dragging_mode = false;
    }

    void addShape(const std::shared_ptr<shape>& new_shape) {
        shapes.push_back(new_shape);
    }

    void setNextShapeToDraw(ShapesToDraw to_draw) {
        next_shape_to_draw = to_draw;
    }

protected:
    void paintEvent(QPaintEvent *) override {
        QPainter painter;
        painter.begin(this);
        for(auto& shape : shapes) {
            shape->paint(painter);
        }
        painter.end();
    }

    void keyPressEvent(QKeyEvent *event) override {
        if (selected_shape && event->key() == Qt::Key_Delete) {
            selected_shape->unselect();
            for (auto it = shapes.begin(); it != shapes.end(); it++) {
                if ((*it) == selected_shape) {
                    shapes.erase(it);
                    selected_shape = nullptr;
                    break;
                }
            }
            update();
        }
    }

    void mousePressEvent(QMouseEvent *event) override {
        if (selected_shape) {
            selected_shape->unselect();
            selected_shape = nullptr;
        }

        if (event->button() == Qt::LeftButton) {
            if (next_shape_to_draw == RectangleShape) {
                addShape(std::make_shared<rectangle>(event->pos().x() - 25, event->pos().y() - 25, 50, 50));
            } else if (next_shape_to_draw == CircleShape) {
                addShape(std::make_shared<circle>(event->pos().x() - 50, event->pos().y() - 50, 50));
            }
            update();
        } else if (event->button() == Qt::RightButton) {
            for (auto it = shapes.rbegin(); it != shapes.rend(); it++) {
                if ((*it)->contains(event->pos().x(), event->pos().y())) {
                    selected_shape = *it;
                    (*it)->select();
                    is_in_dragging_mode = true;
                    previous_x = event->pos().x();
                    previous_y = event->pos().y();
                    break;
                }
            }
            update();
        }
    }

    void mouseMoveEvent(QMouseEvent *event) override{
        if(selected_shape){
           int dx = - previous_x + event->pos().x();
           int dy = - previous_y + event->pos().y();
           selected_shape->move(dx,dy);
            previous_x = event->pos().x();
            previous_y = event->pos().y();
           update();
        }
    }

private:
    std::vector<std::shared_ptr<shape>> shapes;
    ShapesToDraw next_shape_to_draw;
    std::shared_ptr<shape> selected_shape;
    bool is_in_dragging_mode = false;
    int previous_x, previous_y;
};

class QPaintWindow : public QWidget {
public:
    QPaintWindow() {
        auto* window = new QWidget;
        this->setWindowTitle("Problem #5");
        this->resize(500, 500);

        auto* canvas = new QShapeCanvas(this);
        canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        canvas->setFocusPolicy(Qt::StrongFocus);

        auto* toolbar = new QWidget;
        auto* circleButton   = new QPushButton("Circle", toolbar);
        circleButton->setStyleSheet("background-color: white;" "color: black;");
        auto* rectangleButton = new QPushButton("Rectangle", toolbar);
        rectangleButton->setStyleSheet("background-color: white;" "color: black;");

        QObject::connect(rectangleButton, &QPushButton::clicked, [canvas, rectangleButton, circleButton] {
            rectangleButton->setStyleSheet("background-color: red;" "color: white;");
            circleButton->setStyleSheet("background-color: white;" "color: black;");
            canvas->setNextShapeToDraw(QShapeCanvas::ShapesToDraw::RectangleShape);
        });

        QObject::connect(circleButton, &QPushButton::clicked, [canvas, circleButton, rectangleButton] {
            rectangleButton->setStyleSheet("background-color: white;" "color: black;");
            circleButton->setStyleSheet("background-color: red;" "color: white;");
            canvas->setNextShapeToDraw(QShapeCanvas::ShapesToDraw::CircleShape);
        });

        auto* button_layout = new QHBoxLayout(toolbar);
        button_layout->addWidget(circleButton);
        button_layout->addWidget(rectangleButton);

        auto* window_layout = new QVBoxLayout(this);
        window_layout->addWidget(canvas);
        window_layout->addWidget(toolbar);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QPaintWindow window;
    window.show();

    return QApplication::exec();
}

qt graphics c++17 logic
1个回答
0
投票

我通过更改 Circle 类中的 contains 函数来修复它。 现在看起来像这样:

 [[nodiscard]] bool contains(int x, int y) const override {
    int dx = x - m_x-25;
    int dy = y - m_y-25;
    return (dx * dx + dy * dy) <= (m_radius * m_radius);
}
© www.soinside.com 2019 - 2024. All rights reserved.