Qt:依据ChatGpt生成Qt可选择扇形按钮

引言

  因为项目需要绘制一个中间为圆心,包含数个扇形的可选择按钮。正好ChatGpt使用起来比较成熟,因此使用询问的方式得到两部分代码。最终修改后的效果如动图:
在这里插入图片描述

1、生成过程

1.1 饼图

目前ChatGpt给出的代码还有缺陷,一次运行不起来。需要人为添加头文件或处理逻辑关系,不过已经很强大了。
生成的效果为:
在这里插入图片描述

//饼图案例
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QPainter>
#include <QDebug>
#include <QTableWidget>
#include <QHeaderView>
#include <QMessageBox>
#include <QMouseEvent>

class SectorChartButton : public QPushButton {
public:
	SectorChartButton(QTableWidget* tableWidget, QWidget* parent = nullptr) : QPushButton(parent), m_tableWidget(tableWidget) {
		setFixedSize(200, 200);
		setStyleSheet("border: none");
	}

protected:
	void paintEvent(QPaintEvent* event) override {
		Q_UNUSED(event)
			QPainter painter(this);
		painter.setRenderHint(QPainter::Antialiasing);

		// Draw background fan shape
		painter.setPen(Qt::NoPen);
		painter.setBrush(QColor(200, 200, 200));
		painter.drawEllipse(rect());

		// Draw concentric circle
		painter.setPen(QPen(QColor(0, 0, 0), 3));
		painter.setBrush(QColor(255, 255, 255));
		int x = width() / 4;
		int y = height() / 4;
		int w = width() / 2;
		int h = height() / 2;
		painter.drawEllipse(x, y, w, h);

		// Draw fan shapes
		painter.setPen(QPen(QColor(0, 0, 0), 3));
		painter.setBrush(QColor(255, 0, 0));
		painter.drawPie(rect(), 30 * 16, 120 * 16);
		painter.setBrush(QColor(0, 255, 0));
		painter.drawPie(rect(), 150 * 16, 120 * 16);
		painter.setBrush(QColor(0, 0, 255));
		painter.drawPie(rect(), 270 * 16, 120 * 16);

		// Draw lines from center to edge of each fan shape
		painter.drawLine(width() / 2, height() / 2, width() / 2 + (width() - 20) / 4 * qCos(qDegreesToRadians(75)), height() / 2 - (height() - 20) / 4 * qSin(qDegreesToRadians(75)));
		painter.drawLine(width() / 2, height() / 2, width() / 2 - (width() - 20) / 4 * qSin(qDegreesToRadians(60)), height() / 2 + (height() - 20) / 4 * qCos(qDegreesToRadians(60)));
		painter.drawLine(width() / 2, height() / 2, width() / 2 - (width() - 20) / 4 * qCos(qDegreesToRadians(75)), height() / 2 - (height() - 20) / 4 * qSin(qDegreesToRadians(75)));
	}

	void mousePressEvent(QMouseEvent* event) override {
		QRectF rect = this->rect();
		QPointF center = rect.center();
		QPointF pos = event->localPos();
		qreal angle = qRadiansToDegrees(qAtan2(pos.y() - center.y(), pos.x() - center.x())) + 360;
		if (angle >= 30 && angle < 150) {
			m_tableWidget->insertRow(0);
			QTableWidgetItem* item1 = new QTableWidgetItem("Red sector");
			QTableWidgetItem* item2 = new QTableWidgetItem("Column 1 data");
			m_tableWidget->setItem(0, 0, item1);
			m_tableWidget->setItem(0, 1, item2);
			QMessageBox::information(this, "Sector Chart Button", "You clicked on the red sector!");
		}
		else if (angle >= 150 && angle < 270) {
			m_tableWidget->insertRow(0);
			QTableWidgetItem* item1 = new QTableWidgetItem("Green sector");
			QTableWidgetItem* item2 = new QTableWidgetItem("Column 2 data");
			m_tableWidget->setItem(0, 1, item1);
			m_tableWidget->setItem(0, 2, item2);
			QMessageBox::information(this, "Sector Chart Button", "You clicked on the green sector!");
		}
		else if (angle >= 270 || angle < 30) {
			m_tableWidget->insertRow(0);
			QTableWidgetItem* item1 = new QTableWidgetItem("Blue sector");
			QTableWidgetItem* item2 = new QTableWidgetItem("Column 3 data");
			m_tableWidget->setItem(0, 2, item1);
			m_tableWidget->setItem(0, 3, item2);
			QMessageBox::information(this, "Sector Chart Button", "You clicked on the blue sector!");
		}
	}

private:
	QTableWidget* m_tableWidget;
};

int main(int argc, char* argv[]) {
	QApplication app(argc, argv);
	QWidget widget;
	widget.setFixedSize(600, 400);

	// Create table widget
	QTableWidget tableWidget(&widget);
	tableWidget.setColumnCount(4);
	tableWidget.setHorizontalHeaderLabels({ "Column 1", "Column 2", "Column 3", "Column 4" });
	tableWidget.verticalHeader()->setVisible(false);
	tableWidget.setGeometry(250, 50, 300, 300);

	// Create sector chart button
	SectorChartButton* button = new SectorChartButton(&tableWidget, &widget);
	button->move(50, 100);
	button->show();

	widget.show();
	return app.exec();
}

2.2 扇形图

ChatGpt实现效果如下,支持鼠标停留变颜色以及单击保留选择项。
在这里插入图片描述
生成代码:

//扇形图案例

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>

class ColorWheel : public QWidget
{
public:
    ColorWheel(QWidget *parent = nullptr) : QWidget(parent)
    {
        setFixedSize(200, 200);
        setMouseTracking(true);
    }

protected:
    void paintEvent(QPaintEvent*) override
    {
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);

        QRectF rect = QRectF(10, 10, 180, 180);
        qreal startAngle[] = {0, 120, 240};
        qreal spanAngle[] = {120, 120, 120};
        QColor colors[] = {Qt::red, Qt::green, Qt::blue};

        for (int i = 0; i < 3; i++) {
            if (m_hoveredSector == i || m_selectedSector == i) {
                painter.setPen(colors[i]);
                painter.setBrush(colors[i]);
            } else {
                painter.setPen(colors[i].darker());
                painter.setBrush(Qt::NoBrush);
            }
            painter.drawPie(rect, startAngle[i] * 16, spanAngle[i] * 16);
        }
    }

    void mouseMoveEvent(QMouseEvent* event) override
    {
        int x = event->x();
        int y = event->y();
        int sector = getSector(x, y);
        if (sector != m_hoveredSector) {
            m_hoveredSector = sector;
            update();
            if (sector >= 0 && sector < 3) {
                QColor color;
                switch (sector) {
                    case 0: color = Qt::red; break;
                    case 1: color = Qt::green; break;
                    case 2: color = Qt::blue; break;
                }
                qDebug() << "Hovering over sector" << sector << ", color is" << color.name();
            }
        }
    }

    void leaveEvent(QEvent*) override
    {
        m_hoveredSector = -1;
        update();
    }

    void mousePressEvent(QMouseEvent* event) override
    {
        int x = event->x();
        int y = event->y();
        int sector = getSector(x, y);
        if (sector != m_selectedSector) {
            m_selectedSector = sector;
            update();
            if (sector >= 0 && sector < 3) {
                QColor color;
                switch (sector) {
                    case 0: color = Qt::red; break;
                    case 1: color = Qt::green; break;
                    case 2: color = Qt::blue; break;
                }
                qDebug() << "Selected sector" << sector << ", color is" << color.name();
            }
        }
    }

private:
    int getSector(int x, int y)
    {
        int dx = x - 100;
        int dy = y - 100;
        int r = qSqrt(dx*dx + dy*dy);
        if (r < 90) {
            qreal angle = qAtan2(dy, dx) * 180 / M_PI;
            if (angle < 0) angle += 360;
            int sector = static_cast<int>(angle / 120);
            return sector;
        }
        return -1;
    }

    int m_hoveredSector = -1;
    int m_selectedSector = -1;
};

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

    ColorWheel w;
    w.show();

    return a.exec();
}

3.3 可选择扇形按钮

在这里插入图片描述
根据以上代码修正后得到该按钮,代码如下:

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>

class ColorWheel : public QWidget
{
public:
	ColorWheel(QWidget* parent = nullptr) : QWidget(parent)
	{
		setFixedSize(200, 200);
		setMouseTracking(true);
	}

protected:
	void paintEvent(QPaintEvent*) override
	{
		QPainter painter(this);
		painter.setRenderHint(QPainter::Antialiasing);

		QRectF rect = QRectF(10, 10, 180, 180);
		qreal startAngle[] = { 90, 210, 330 };
		qreal spanAngle[] = { 120, 120, 120 };
		QColor colors[] = { Qt::red, Qt::green, Qt::blue };

		int x = width() / 4;
		int y = height() / 4;
		int w = width() / 2;
		int h = height() / 2;
		QRectF innerRect = QRectF(x, y, w, h);

		if (m_init)
		{
			//默认绘制第一个图形
			painter.setPen(colors[0]);
			painter.setBrush(Qt::NoBrush);
			painter.drawPie(rect, startAngle[0] * 16, spanAngle[0] * 16);

			// Draw concentric circle
			painter.setPen(Qt::NoPen);
			painter.setBrush(QColor(255, 255, 255));
			painter.drawEllipse(x, y, w, h);

			painter.setPen(colors[0]);
			painter.drawArc(innerRect, startAngle[0] * 16, spanAngle[0] * 16);
		}


		for (int i = 0; i < 3; i++) {
			if (m_hoveredSector == i || m_selectedSector == i) {
				painter.setPen(colors[i]);
				painter.setBrush(Qt::NoBrush);
				painter.drawPie(rect, startAngle[i] * 16, spanAngle[i] * 16);

				// Draw concentric circle
				painter.setPen(Qt::NoPen);
				painter.setBrush(QColor(255, 255, 255));
				painter.drawEllipse(x, y, w, h);

				painter.setPen(colors[i]);
				painter.drawArc(innerRect, startAngle[i] * 16, spanAngle[i] * 16);

				m_lastSelect = m_selectedSector;
			}
			else {
				painter.setPen(colors[i].darker());
				painter.setBrush(Qt::NoBrush);
			}
			//painter.drawPie(rect, startAngle[i] * 16, spanAngle[i] * 16);
		}

		if (!m_init && (m_selectedSector == -1))
		{
			//保留之前的选择
			painter.setPen(colors[m_lastSelect]);
			painter.setBrush(Qt::NoBrush);
			painter.drawPie(rect, startAngle[m_lastSelect] * 16, spanAngle[m_lastSelect] * 16);

			// Draw concentric circle
			painter.setPen(Qt::NoPen);
			painter.setBrush(QColor(255, 255, 255));
			painter.drawEllipse(x, y, w, h);

			painter.setPen(colors[m_lastSelect]);
			painter.drawArc(innerRect, startAngle[m_lastSelect] * 16, spanAngle[m_lastSelect] * 16);
		}
		m_init = false;
	}

	//void mouseMoveEvent(QMouseEvent* event) override
	//{
	//	int x = event->x();
	//	int y = event->y();
	//	int sector = getSector(x, y);
	//	if (sector != m_hoveredSector) {
	//		m_hoveredSector = sector;
	//		update();
	//		if (sector >= 0 && sector < 3) {
	//			QColor color;
	//			switch (sector) {
	//			case 0: color = Qt::red; break;
	//			case 1: color = Qt::green; break;
	//			case 2: color = Qt::blue; break;
	//			}
	//			qDebug() << "Hovering over sector" << sector << ", color is" << color.name();
	//		}
	//	}
	//}

	//void leaveEvent(QEvent*) override
	//{
	//	m_hoveredSector = -1;
	//	update();
	//}

	void mousePressEvent(QMouseEvent* event) override
	{
		int x = event->x();
		int y = event->y();
		int sector = getSector(x, y);
		if (sector != m_selectedSector) {
			m_selectedSector = sector;
			update();
			if (sector >= 0 && sector < 3) {
				QColor color;
				switch (sector) {
				case 0: color = Qt::red; break;
				case 1: color = Qt::green; break;
				case 2: color = Qt::blue; break;
				}
				qDebug() << "Selected sector" << sector << ", color is" << color.name();
			}
		}
	}

private:
	int getSector(int x, int y)
	{
		int dx = x - 100;
		int dy = y - 100;
		int r = qSqrt(dx * dx + dy * dy);
		if (r < 90) {
			qreal angle = qAtan2(-dy, dx) * 180 / M_PI;
			if (angle < 90) angle += 360;
			int sector = static_cast<int>((angle - 90) / 120);
			return sector;
		}
		return -1;
	}

	int m_hoveredSector = -1;
	int m_selectedSector = -1;
	bool m_init = true;
	int m_lastSelect = -1;
};

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

	ColorWheel w;
	w.show();

	return a.exec();
}

1.4 新的扇形画法*GraphicItem

可以通过QPainterPath和QRegion的方式来绘制。QPatinterPath含有substrate方法,然后通过QPainter绘制。同时QRegion也有对应的直接使用QPainter绘制的方法。setClipRegion可以设置当前可绘画的区域。

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);
    QPainterPath path; // 定义QPainterPath对象

    int x = width() / 2;  // 获取widget的宽度
    int y = height() / 2; // 获取widget的高度
    int radius = qMin(x, y); // 确定半径

    QRectF rect(x - radius, y - radius, radius * 2, radius * 2); // 定义外接矩形

    path.moveTo(x, y); // 将起点移动到圆心
    path.arcTo(rect, 90, -120); // 添加90到210度的椭圆弧线,注意这里的角度单位是以1/16度来表示的
    path.lineTo(x, y); // 将路径连接回中心点

    int smallRadius = radius / 2; // 定义小扇形的半径
    QRectF smallRect(x - smallRadius, y - smallRadius, smallRadius * 2, smallRadius * 2); // 定义小扇形的外接矩形

    QPainterPath smallPath; // 定义小扇形的路径
    smallPath.moveTo(x, y); // 将起点移动到圆心
    smallPath.arcTo(smallRect, 90, -120); // 添加90到210度的椭圆弧线,注意这里的角度单位是以1/16度来表示的

    QRegion bigRegion(path.toFillPolygon().toPolygon()); // 定义大扇形的QRegion
    QRegion smallRegion(smallPath.toFillPolygon().toPolygon()); // 定义小扇形的QRegion
    bigRegion = bigRegion.subtracted(smallRegion); // 大扇形减去小扇形

    QBrush brush(Qt::NoBrush); // 创建空画刷
    painter.setBrush(brush); // 设置画刷为空,即不填充图形

    QPen pen(Qt::black); // 定义画笔,颜色为黑色
    pen.setWidth(2); // 设置画笔宽度
    painter.setPen(pen); // 设置画笔

    painter.setClipRegion(bigRegion); // 设置绘制区域
    painter.drawPath(path); // 绘制大扇形的路径轮廓

    painter.setClipping(false); // 取消原来的绘制区域
    painter.setClipRegion(smallRegion); // 设置绘制区域为小扇形的QRegion
    painter.drawPath(smallPath); // 绘制小扇形的路径轮廓
}


2、训练过程

  这里给出了训练过程,目前中文语料比较少,因此得到的有效信息不充足。所以每次都是中文翻译为英语后去问答,出乎意料的是代码基本修改下都能跑起来。
在这里插入图片描述

3、错误原因

  如果指出ChatGPT的错误,它会给出部分错误原因,虽然有时候和给出的错误原因不太符合代码,但在后续自己Debug的过程中能发现很多有用的信息。如在计算角度使用QAtan2 时应取-dy。

In this modified code, a new m_selectedSector variable has been added to track which sector is currently selected by the user (i.e. the one the user clicked on). The paintEvent() method has also been updated to fill in the color of the selected sector even when the mouse is not moving. This is done by checking whether m_selectedSector is equal to the current sector being painted (i), and if so, filling in the sector with its color.

In addition, a new mousePressEvent() method has been added to handle the case where the user clicks on a sector. When this happens, m_selectedSector is updated, and the widget is repainted with the selected sector filled in with its color. The code also outputs the color of the selected sector to the console using qDebug().

Finally, the leaveEvent() method has been updated to reset both m_hoveredSector and m_selectedSector to -1 when the mouse leaves the widget, which causes all of the sectors to be drawn with no fill color.

在此修改后的代码中,添加了一个新的m_selectedSector变量来跟踪用户当前选择的扇区(即用户单击的扇区)。paintEvent() 方法也已更新,即使在鼠标不移动时也能填充所选扇区的颜色。这是通过检查m_selectedSector是否等于当前正在绘制的扇区 (i) 来完成的,如果是,则用其颜色填充扇区。 此外,还添加了一个新的 mousePressEvent() 方法来处理用户单击扇区的情况。发生这种情况时,m_selectedSector将更新,并且小部件将重新绘制,并用其颜色填充所选扇区。该代码还使用 qDebug() 将所选扇区的颜色输出到控制台。 最后,当鼠标离开小部件时,leaveEvent() 方法已更新为将 m_hoveredSector 和 m_selectedSector 重置为 -1,这会导致绘制所有扇区时没有填充颜色。

The error was caused by a mistake in the calculation of the angle variable. Instead of using +dy, it should be -dy, since the y-axis is inverted in the coordinate system used by QPainter (i.e. positive y is downwards). This causes the angle to be calculated correctly, which in turn allows the correct sector to be determined based on the angle.

I hope this corrected method works better for you. Please let me know if you have any further questions or issues.

该错误是由角度变量计算错误引起的。它不应该使用 +dy,而应该是 -dy,因为 y 轴在 QPainter 使用的坐标系中是反转的(即正 y 向下)。这会导致正确计算角度,从而允许根据角度确定正确的扇区。 我希望这种更正后的方法对您更有效。如果您有任何其他问题或问题,请告诉我。

The issue with the previous implementation was that it incorrectly assumed that sector 1 starts at 120 degrees and sector 2 starts at 240 degrees, which causes the two sectors to be calculated inversely. The corrected implementation addresses this issue by correctly identifying sector 1 as the sector starting at 30 degrees, and sector 2 as the sector starting at 150 degrees.

I apologize for any confusion caused by my earlier responses, and I hope this updated implementation resolves the issue. Please let me know if you have any further questions or concerns.

先前实现的问题在于,它错误地假定扇区 1 从 120 度开始,扇区 2 从 240 度开始,这会导致两个扇区的计算相反。更正后的实现通过正确标识扇区 1 作为从 30 度开始的扇区,将扇区 2 标识为从 150 度开始的扇区来解决此问题。 对于我之前的回复造成的任何混乱,我深表歉意,我希望这个更新的实现可以解决这个问题。如果您有任何其他问题或疑虑,请告诉我。

4、涉及知识点

------待更新-------------------------------------------------

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

面条有点辣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值