Qt开发 | Qt绘图技术 | 常见图像绘制 | Qt移动鼠标绘制任意形状 | Qt绘制带三角形箭头的窗口

文章目录

  • 一、基本绘图技术介绍
  • 二、常见的18种图形、路径、文字、图片绘制
  • 三、Qt移动鼠标绘制任意形状
  • 四、Qt绘制带三角形箭头的窗口

一、基本绘图技术介绍

  Qt提供了绘图技术,程序员可以在界面上拖动鼠标,或者在代码里指定参数进行绘图。

Qt绘图技术介绍

  • QPainter

    基本要素

    • QPen:用于控制线条的颜色、宽度、线型等;

      • 宽度(Width):
        • 通过 setWidth() 方法设置画笔的宽度,这将决定绘制线条的粗细。
      • 颜色(Color):
        • 使用 setColor() 方法设置画笔的颜色。颜色可以是 Qt 命名的颜色常量,如 Qt::red,或者使用 QColor 对象定义的更具体的颜色。
      • 样式(Style):
        • setStyle() 方法定义了线条的样式。可以是实线(Qt::SolidLine)、虚线(Qt::DashLine)、点线(Qt::DotLine)等。
      • 端点样式(Cap Style):
        • setCapStyle() 方法设置线条端点的样式。常见的端点样式有方形(Qt::SquareCap)、圆形(Qt::RoundCap)和平面(Qt::FlatCap)。
      • 连接样式(Join Style):
        • setJoinStyle() 方法定义了线条连接处的样式。斜接(Qt::MiterJoin)是默认样式,适用于大多数情况。还可以选择圆角(Qt::RoundJoin)或斜切(Qt::BevelJoin)。
      • 线型(Dash Pattern):
        • 对于虚线或点线,可以通过 setDashPattern() 方法设置具体的虚线模式,例如定义点和间隔的长度。
      • 笔刷(Brush):
        • 虽然 QPen 主要用于线条,但它也有一个 setBrush() 方法,可以设置用于填充形状轮廓的画刷样式。
      • 使用 QPen:
        • 创建 QPen 对象后,可以通过上述方法设置其属性,然后通过 QPainter::setPen() 方法将其应用到 QPainter 对象上。之后,QPainter 将使用这个画笔的样式来绘制线条和形状的轮廓。

      示例:

      QPainter painter;
      Qpen pen;//设置画笔属性
      pen.setWidth(10);  		//设置画笔的宽度为10像素。
      pen.setColor(Qt::red);	//设置画笔的颜色为红色
      pen.setStyle(Qt::SolidLine);    //设置画笔的样式为实线
      pen.setCapStyle(Qt::SquareCap);	//设置画笔端点的样式为方形
      pen.setJoinStyle(Qt::MiterJoin); // 设置画笔线条连接处的样式为斜接,这是最常用的线条连接方式,适用于大多数情况。painter.setPen(pen);    //将设置好的QPen对象应用到QPainter对象上
      
    • QBrush:设置区域填充特性,可以设置填充颜色、填充方式、渐变特性等,还可以采用图片做纹理填充

      • 颜色设置:
        • QBrush 可以通过 setColor() 方法设置填充颜色。颜色可以使用 QColor 对象指定,提供广泛的颜色选择。
      • 填充样式:
        • setStyle()方法用于设置填充样式。Qt::BrushStyle枚举提供了多种预定义的填充样式,如:
          • Qt::SolidPattern:纯色填充。
          • Qt::HorizontalPatternQt::VerticalPattern:水平或垂直条纹填充。
          • Qt::CrossPatternQt::BDiagPattern:交叉或对角线条纹填充。
          • Qt::DenseNPattern:提供不同密度的条纹或点状图案。
      • 渐变填充:
        • QBrush 支持使用渐变作为填充模式。可以创建 QLinearGradientQRadialGradient 对象,并将其设置为 QBrush 的渐变属性。
      • 纹理填充:
        • 通过 setTexture() 方法,可以将 QPixmapQImage 对象设置为纹理,用于填充形状。
      • 透明度:
        • setOpacity() 方法允许设置填充的透明度,范围从 0(完全透明)到 1(完全不透明)。
      • 变换:
        • setTransform() 方法可以对 QBrush 应用变换,如旋转、缩放等,这会影响纹理或渐变在形状上的呈现方式。
      • 使用 QBrush:
        • 在绘制过程中,一旦 QBrush 对象被设置好,就可以通过QPainter::setBrush() 方法将其应用到 QPainter 对象上。随后,使用 QPainter 绘制的封闭形状将使用该画刷进行填充。

      示例:

      QPainter painter;
      QBrush brush;brush.setColor(Qt::yellow); // 设置为黄色
      brush.setStyle(Qt::SolidPattern);	//设置填充样式为纯色填充painter.setBrush(brush);
      
    • QFont:绘制文字时,设置文字的字体样式、大小等属性

      • 字体名称(Family):
        • 使用 setFamily() 方法设置字体的名称,如 “Arial”、“Times New Roman” 等。
      • 字体大小(Size):
        • setPointSize() 方法用于设置字体的大小,通常以点为单位。
      • 字体风格(Style):
        • setStyle() 方法可以设置字体的风格,如 QFont::StyleNormalQFont::StyleItalic 等。
      • 字体粗细(Weight):
        • 使用 setWeight() 方法设置字体的粗细,如 QFont::LightQFont::NormalQFont::Bold
      • 字体拉伸(Stretch):
        • setStretch() 方法用于设置字体的宽度拉伸,可以使得字体更宽或更窄。
      • 字体间距(Kerning):
        • setKerning() 方法可以启用或禁用字符间距调整,影响字符之间的空间。
      • 字体字距(Letter Spacing):
        • setLetterSpacing() 方法设置字符之间的水平间距。
      • 文本方向(Text Direction):
        • setStyleStrategy() 方法可以设置文本的方向,如从左到右或从右到左。
      • 固定宽度字体(Fixed Pitch):
        • setFixedPitch() 方法用于设置是否使用固定宽度字体。
      • 使用 QFont:
        • 创建 QFont 对象后,可以通过上述方法设置其属性,然后通过 QPainter::setFont() 方法将其应用到 QPainter 对象上。之后,使用 QPainter 绘制的文本将使用这个字体。

      示例:

      QFont font;
      font.setFamily("Helvetica");
      font.setPointSize(12);
      font.setBold(true); // 设置为粗体
      font.setStyleItalic(true); // 设置为斜体QPainter painter;
      painter.setFont(font);
      painter.drawText(10, 20, "Hello, World!"); // 使用字体绘制文本
      
    • 渐变填充

      • QLinearGradient线性渐变填充,颜色沿着直线从一点渐变到另一点。可以指定起点和终点,以及中间的颜色停止点来创建平滑的颜色过渡。

        • 起点和终点:
          • QLinearGradient 需要两个点来定义渐变的方向和范围:起始点和终点。渐变的颜色将从起始点开始,向终点过渡。
        • 颜色停止:
          • 使用 setColorAt() 方法可以设置颜色在渐变中的停止点。这个方法接受一个0到1之间的值,表示从起始点到终点的相对位置,以及一个 QColor 对象,表示该位置的颜色。
        • 渐变坐标系统:
          • 渐变的坐标系统可以是对象坐标系或绝对坐标系。通过 setCoordinateMode() 方法可以设置渐变的坐标模式。
        • 坐标模式:
          • QLinearGradient支持两种坐标模式:
            • ObjectBoundingMode:渐变是相对于使用渐变的对象的边界框。
            • StretchToDeviceMode:渐变是相对于整个设备(如画布或窗口)的尺寸。
        • 使用 QLinearGradient:
          • 创建 QLinearGradient 对象后,设置起始点、终点和颜色停止点,然后将它作为 QBrush 对象的样式来使用。

        示例:

        QLinearGradient gradient(0, 0, 100, 100); // 定义从左到右的渐变
        gradient.setColorAt(0.0, QColor("red"));    // 起始颜色为红色
        gradient.setColorAt(1.0, QColor("blue"));   // 结束颜色为蓝色QBrush brush(gradient); // 创建一个使用渐变的画刷
        QPainter painter;
        painter.setBrush(brush);
        painter.drawRect(10, 10, 100, 100); // 使用画刷填充矩形
        
      • QRadialGradient:径向渐变填充,颜色从中心点向外辐射,形成一个圆形或椭圆形的渐变效果。这种渐变通常用于创建按钮或图标的立体感。

      • QConicalGradient:圆锥形渐变填充,颜色从一个点向外辐射,但与径向渐变不同,圆锥形渐变的颜色过渡是沿着圆锥的侧面进行的,而不是沿着半径。这种渐变较少使用,但可以创造出独特的视觉效果。

  • QPaintDevice

    是一个可以使用QPainter进行绘图的抽象的二维界面

    常用的绘图设备:

    • QWidget
    • QPixmap、QImage:可用来绘制视频图片数据
  • QPaintEngine

    • 给QPainter提供在不同设备上绘图的接口
    • 应用程序一般无需与QPaintEngine打交道
    • 可以禁用QPaintEngine,使用DX或OPenGL自渲染
  • 绘图事件paintEvent()

    绘图事件,需要用户override

  • 坐标系:原点在左上角,x向左为正,y向下为正

  • 基本的绘图元素

    在Qt框架中,这些操作是通过QPainter类实现的。QPainter是一个低级的绘图类,提供了丰富的方法来绘制线条、形状、文本和图像。使用QPainter时,你通常会先创建一个QPainter对象,然后设置画笔、画刷等属性,最后调用相应的绘图函数来绘制内容。

      • drawPoint: 用于绘制单个点。
      • drawPoints: 用于绘制多个点。通常需要一个点的数组或列表作为参数。
    • 线
      • 直线: drawLine 用于绘制直线。通常需要两个点(起点和终点)作为参数。
      • 圆弧: drawArc 用于绘制圆或椭圆的一部分,即圆弧。需要指定圆心、半径、起始角度和结束角度。
    • 封闭的图形
      • 矩形
        • 普通矩形:drawRect: 用于绘制一个矩形的边框或填充整个矩形。
        • 圆角矩形:drawRoundedRect: 用于绘制带有圆角的矩形。
      • 弧弦:drawChord 用于绘制一个圆弧以及与圆弧两端点相连的直线,形成一个封闭的图形
      • 椭圆: drawEllipse 用于绘制椭圆的边框或填充整个椭圆
    • 任意路径绘制
      • drawPolygon:绘制一个多边形。传入的点列表中最后一个点会自动与第一个点相连,形成一个闭合的多边形。
      • drawPolyline:与drawPolygon类似,drawPolyline用于绘制一系列点连接成的折线,但最后一个点不会与第一个点相连,因此结果是开放的。
      • drawConvexPolygon:用于绘制任意凸多边形。凸多边形是指任意两个顶点之间的线段都不会与其他顶点相交的多边形。
      • drawLines:绘制一系列的线段。你需要传入一系列的起点和终点来定义这些线段。
      • drawPath:用于绘制更复杂的路径,可以包含直线段、曲线段等
      • drawPie:用于绘制扇形,即圆的一部分。你需要指定圆心、半径、起始角度和结束角度来定义扇形。
    • 图片绘制
      • drawPixmap: 用于在指定位置绘制QPixmap对象,QPixmap是Qt中用于存储图像数据的类。
      • drawImage: 类似于drawPixmap,但用于绘制QImage对象,QImage是另一个图像类,通常用于处理像素数据。
    • 绘制文本
      • drawText: 用于在指定位置绘制文本。你可以指定文本内容、位置、对齐方式等属性。
    • 其他操作
      • eraseRect: 用于擦除指定矩形区域内的内容,通常是用当前画笔的背景色来填充这个区域。
      • fillPath: 用于填充由QPainterPath定义的路径。如果设置了画笔颜色,路径内部会被填充,但不会绘制路径的轮廓线。
      • fillRect: 用于填充一个矩形区域,如果设置了画笔样式,矩形的边框也会被绘制。

二、常见的18种图形、路径、文字、图片绘制

  利用QTreeView类的信号void clicked(const QModelIndex &index);得到要绘制的图形,触发槽函数,槽函数用于设置绘图样式并调用update()函数触发paintEvent()绘图事件函数,在该函数中绘制已选择的图形。

示例:

drawtype.h

#pragma once
//基本画图枚举
enum class DRAW_TYPE
{point,multipoints,line,arc,rect,roundrect,chord,ellipse,polygon,polyline,ConvexPloygon,lines,path,pie,image,pixmap,draw_text,draw_erase,draw_fillpath,draw_fillrect
};

CPaintWidget.h

#pragma once
#include <QWidget>
#include "drawtype.h"class CPaintWidget : public QWidget
{Q_OBJECTpublic:CPaintWidget(QWidget* p = nullptr);~CPaintWidget() {}void setDrawType(DRAW_TYPE type);   //设置绘图类型private:void paintEvent(QPaintEvent* event) override; //绘图事件private:/* 绘制基本图形 */void draw_point();void draw_multipoints();void draw_line();void draw_arc();void draw_rect();void draw_roundrect();void draw_chord();void draw_ellipse();void draw_polygon();void draw_polyline();void draw_ConvexPloygon();void draw_lines();void draw_path();void draw_pie();void draw_image();void draw_pixmap();void draw_text();void draw_erase();void draw_fillpath();void draw_fillrect();private:DRAW_TYPE m_drawType;int W = 0;int H = 0;
};

CPaintWidget.cpp

#include "CPaintWidget.h"
#include <QPainter>
#include <QPainterPath>CPaintWidget::CPaintWidget(QWidget* p):QWidget(p)
{this->setMinimumSize(800, 600);m_drawType = DRAW_TYPE::polygon;
}void CPaintWidget::paintEvent(QPaintEvent* event)
{W = this->width();H = this->height();switch (m_drawType){case DRAW_TYPE::point:draw_point();break;case DRAW_TYPE::multipoints:draw_multipoints();break;case DRAW_TYPE::line:draw_line();break;case DRAW_TYPE::arc:draw_arc();break;case DRAW_TYPE::rect:draw_rect();break;case DRAW_TYPE::roundrect:draw_roundrect();break;case DRAW_TYPE::chord:draw_chord();break;case DRAW_TYPE::ellipse:draw_ellipse();break;case DRAW_TYPE::polygon:draw_polygon();break;case DRAW_TYPE::polyline:draw_polyline();break;case DRAW_TYPE::ConvexPloygon:draw_ConvexPloygon();break;case DRAW_TYPE::lines:draw_lines();break;case DRAW_TYPE::path:draw_path();break;case DRAW_TYPE::pie:draw_pie();break;case DRAW_TYPE::image:draw_image();break;case DRAW_TYPE::pixmap:draw_pixmap();break;case DRAW_TYPE::draw_text:draw_text();break;case DRAW_TYPE::draw_erase:draw_erase();break;case DRAW_TYPE::draw_fillpath:draw_fillpath();break;case DRAW_TYPE::draw_fillrect:draw_fillrect();break;default:break;}
}void CPaintWidget::draw_point()
{QPainter painter(this);QPen pen;pen.setWidth(10);pen.setColor(Qt::red);pen.setStyle(Qt::SolidLine);painter.setPen(pen);painter.drawPoint(QPoint(W / 2, H / 2));
}void CPaintWidget::draw_multipoints()
{QPainter painter(this);QPen pen;pen.setWidth(10);pen.setColor(Qt::blue);pen.setStyle(Qt::SolidLine);painter.setPen(pen);// 画很多点QPoint points[] = {QPoint(5 * W / 12,H / 4),QPoint(3 * W / 4, 5 * H / 12),QPoint(2 * W / 4, 5 * H / 12) };painter.drawPoints(points, 3);
}void CPaintWidget::draw_line()
{QPainter painter(this);//QLine Line(W / 4, H / 4, W / 2, H / 2);QLine Line(W / 4, H / 4, W / 2, H / 4);painter.drawLine(Line);
}void CPaintWidget::draw_arc()
{QPainter painter(this);QRect rect(W / 4, H / 4, W / 2, H / 2);int startAngle = 90 * 16;int spanAngle = 90 * 16;       //旋转 90°painter.drawArc(rect, startAngle, spanAngle);
}void CPaintWidget::draw_rect()
{QPainter painter(this);// 画矩形QRect rect(W / 4, H / 4, W / 2, H / 2);painter.drawRect(rect);
}void CPaintWidget::draw_roundrect()
{QPainter painter(this);// 画圆角矩形QRect rect(W / 4, H / 4, W / 2, H / 2);painter.drawRoundedRect(rect, 20, 20);
}void CPaintWidget::draw_chord()
{QPainter painter(this);QRect rect(W / 4, H / 4, W / 2, H / 2);int startAngle = 90 * 16;int spanAngle = 90 * 16;painter.drawChord(rect, startAngle, spanAngle);
}void CPaintWidget::draw_ellipse()
{QPainter painter(this);QRect rect(W / 4, H / 4, W / 2, H / 2);painter.drawEllipse(rect);
}void CPaintWidget::draw_polygon()
{QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);QPen pen;pen.setWidth(10);pen.setColor(Qt::red);pen.setStyle(Qt::SolidLine);pen.setCapStyle(Qt::SquareCap);pen.setJoinStyle(Qt::MiterJoin);  //画笔断点的样式painter.setPen(pen);QBrush brush;brush.setColor(Qt::yellow);brush.setStyle(Qt::SolidPattern);painter.setBrush(brush);// 画多边形,最后一个点会和第一个点闭合QPoint points[] = {QPoint(5 * W / 12,H / 4),QPoint(3 * W / 4,5 * H / 12),QPoint(5 * W / 12,3 * H / 4),QPoint(2 * W / 4,5 * H / 12) };painter.drawPolygon(points, 4);
}void CPaintWidget::draw_polyline()
{QPainter painter(this);// 画多点连接的线,最后一个点不会和第一个点连接QPoint points[] = {QPoint(5 * W / 12, H / 4),QPoint(3 * W / 4, 5 * H / 12),QPoint(5 * W / 12, 3 * H / 4),QPoint(2 * W / 4, 5 * H / 12)};painter.drawPolyline(points, 4);
}void CPaintWidget::draw_ConvexPloygon()
{QPainter painter(this);QPoint points[4] = {QPoint(5 * W / 12, H / 4),QPoint(3 * W / 4, 5 * H / 12),QPoint(5 * W / 12, 3 * H / 4),QPoint(W / 4, 5 * H / 12)};painter.drawConvexPolygon(points, 4);
}void CPaintWidget::draw_lines()
{QPainter painter(this);// 画一批直线QRect rect(W / 4, H / 4, W / 2, H / 2);QVector<QLine> Lines;Lines.append(QLine(rect.topLeft(), rect.bottomRight()));Lines.append(QLine(rect.topRight(), rect.bottomLeft()));Lines.append(QLine(rect.topLeft(), rect.bottomLeft()));Lines.append(QLine(rect.topRight(), rect.bottomRight()));painter.drawLines(Lines);
}void CPaintWidget::draw_path()
{QPainter painter(this);// 绘制由QPainterPath对象定义的路线QRect rect(W / 4, H / 4, W / 2, H / 2);QPainterPath path;path.addEllipse(rect);path.addRect(rect);painter.drawPath(path);
}void CPaintWidget::draw_pie()
{QPainter painter(this);// 绘制扇形QRect    rect(W / 4, H / 4, W / 2, H / 2);int startAngle = 40 * 16; //起始 40。int spanAngle = 120 * 16; //旋转 120。 painter.drawPie(rect, startAngle, spanAngle);
}void CPaintWidget::draw_image()
{QPainter painter(this);// 在指定的矩形区域内绘制图片QRect rect(W / 4, H / 4, W / 2, H / 2);QImage image(":/resources/tupian.png");painter.drawImage(rect, image);
}void CPaintWidget::draw_pixmap()
{QPainter painter(this);// 绘制Pixmap图片QRect    rect(W / 4, H / 4, W / 2, H / 2);QPixmap    pixmap(":/resources/tupix.png");painter.drawPixmap(rect, pixmap);
}void CPaintWidget::draw_text()
{QPainter painter(this);// 绘制文本,只能绘制单行文字,字体的大小等属性由QPainter::font()决定。QRect rect(W / 4, H / 4, W / 2, H / 2);QFont font;font.setPointSize(30);font.setBold(true);painter.setFont(font);painter.drawText(rect, "Hello,Qt");
}void CPaintWidget::draw_erase()
{QPainter painter(this);// 擦除某个矩形区域,等效于用背景色填充该区域QRect rect(W / 4, H / 4, W / 2, H / 2);painter.eraseRect(rect);
}void CPaintWidget::draw_fillpath()
{QPainter painter(this);// 填充某个QPainterPath定义的绘图路径,但是轮廓线不显示QRect rect(W / 4, H / 4, W / 2, H / 2);QPainterPath path;path.addEllipse(rect);path.addRect(rect);painter.fillPath(path, Qt::red);
}void CPaintWidget::draw_fillrect()
{QPainter painter(this);// 填充一个矩形,无边框线QRect rect(W / 4, H / 4, W / 2, H / 2);painter.fillRect(rect, Qt::green);
}void CPaintWidget::setDrawType(DRAW_TYPE type)
{m_drawType = type;
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <memory>
#include <QTreeView>
#include "CPaintWidget.h"using namespace std;class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:void treeView();private slots:void treeViewExpand(const QModelIndex &index);private:QTreeView* m_pLeftTree = nullptr;CPaintWidget* m_pPaintWidget = nullptr;
};#endif // WIDGET_H

widget.cpp

#pragma execution_character_set("utf-8")#include "widget.h"
#include <QStandardItemModel>
#include <QHBoxLayout>
#include "drawtype.h"Widget::Widget(QWidget* parent): QWidget(parent)
{setWindowTitle(u8"draw all");QHBoxLayout* pHLay = new QHBoxLayout(this);m_pLeftTree = new QTreeView(this);m_pLeftTree->setEditTriggers(QAbstractItemView::NoEditTriggers);  //设置不可编辑m_pLeftTree->setFixedWidth(300);m_pPaintWidget = new CPaintWidget(this);pHLay->addWidget(m_pLeftTree);pHLay->addWidget(m_pPaintWidget);treeView();
}Widget::~Widget()
{}void Widget::treeView()
{m_pLeftTree->setFrameShape(QFrame::NoFrame);QStandardItemModel* model = new QStandardItemModel(m_pLeftTree);model->setHorizontalHeaderLabels(QStringList() << "draw all");QStandardItem* pParentItem = NULL;QStandardItem* pChildItem = NULL;// 点pParentItem = new QStandardItem(QIcon(":/resources/point.png"), "draw ponit");model->appendRow(pParentItem);pChildItem = new QStandardItem(QIcon(":/resources/point.png"), "point");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/multipoints.png"), "multipoints");pParentItem->appendRow(pChildItem);// 线pParentItem = new QStandardItem(QIcon(":/resources/line.png"), "draw line");model->appendRow(pParentItem);pChildItem = new QStandardItem(QIcon(":/resources/line.png"), "line");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/arc.png"), "arc");pParentItem->appendRow(pChildItem);// 封闭的图形pParentItem = new QStandardItem(QIcon(":/resources/rect.png"), "draw rect");model->appendRow(pParentItem);pChildItem = new QStandardItem(QIcon(":/resources/rect.png"), "rect");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/roundrect.png"), "roundrect");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/chord.png"), "chord");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/ellipse.png"), "ellipse");pParentItem->appendRow(pChildItem);// 任意路径绘制pParentItem = new QStandardItem(QIcon(":/resources/polygon.png"), "draw polygon");model->appendRow(pParentItem);pChildItem = new QStandardItem(QIcon(":/resources/polygon.png"), "polygon");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/polyline.png"), "polyline");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/ConvexPloygon.png"), "ConvexPloygon");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/lines.png"), "lines");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/path.png"), "path");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/pie.png"), "pie");pParentItem->appendRow(pChildItem);// 图片绘制pParentItem = new QStandardItem(QIcon(":/resources/image.png"), "draw image");model->appendRow(pParentItem);pChildItem = new QStandardItem(QIcon(":/resources/image.png"), "image");pParentItem->appendRow(pChildItem);pChildItem = new QStandardItem(QIcon(":/resources/pixmap.png"), "pixmap");pParentItem->appendRow(pChildItem);// 文本绘制pParentItem = new QStandardItem(QIcon(":/resources/text.png"), "draw text");model->appendRow(pParentItem);// 擦除pParentItem = new QStandardItem(QIcon(":/resources/erase.png"), "draw erase");model->appendRow(pParentItem);// 路径填充pParentItem = new QStandardItem(QIcon(":/resources/fillpath.png"), "draw fillpath");model->appendRow(pParentItem);// 矩形填充pParentItem = new QStandardItem(QIcon(":/resources/fillrect.png"), "draw fillrect");model->appendRow(pParentItem);m_pLeftTree->setModel(model);   //设置要展示的模型connect(m_pLeftTree, &QAbstractItemView::clicked, this, &Widget::treeViewExpand);
}void Widget::treeViewExpand(const QModelIndex& index)
{QString text = index.data().toString();if (text.compare("point") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::point);/*调用QWidget的update()函数触发重写 paintEvent() 函数*/m_pPaintWidget->update();  //不更新就不会立即显示}else if (text.compare("multipoints") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::multipoints);m_pPaintWidget->update();  }else if (text.compare("line") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::line);m_pPaintWidget->update();}else if (text.compare("arc") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::arc);m_pPaintWidget->update();}else if (text.compare("rect") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::rect);m_pPaintWidget->update();}else if (text.compare("roundrect") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::roundrect);m_pPaintWidget->update();}else if (text.compare("chord") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::chord);m_pPaintWidget->update();}else if (text.compare("ellipse") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::ellipse);m_pPaintWidget->update();}else if (text.compare("polygon") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::polygon);m_pPaintWidget->update();}else if (text.compare("polyline") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::polyline);m_pPaintWidget->update();}else if (text.compare("ConvexPloygon") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::ConvexPloygon);m_pPaintWidget->update();}else if (text.compare("lines") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::lines);m_pPaintWidget->update();  }else if (text.compare("path") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::path);m_pPaintWidget->update();}else if (text.compare("pie") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::pie);m_pPaintWidget->update();}else if (text.compare("image") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::image);m_pPaintWidget->update();}else if (text.compare("pixmap") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::pixmap);m_pPaintWidget->update();}else if (text.compare("draw text") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::draw_text);m_pPaintWidget->update();}else if (text.compare("draw erase") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::draw_erase);m_pPaintWidget->update();}else if (text.compare("draw fillpath") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::draw_fillpath);m_pPaintWidget->update();}else if (text.compare("draw fillrect") == 0){m_pPaintWidget->setDrawType(DRAW_TYPE::draw_fillrect);m_pPaintWidget->update();}
}

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

运行结果

image-20240709161702260

三、Qt移动鼠标绘制任意形状

  在Qt中,实现移动鼠标绘制任意形状通常涉及到鼠标事件的处理,如 mousePressEventmouseMoveEventmouseReleaseEventmouseDoubleClickEventpaintEvent

void paintEvent(QPaintEvent *) override;
void mousePressEvent(QMouseEvent *e) override;       //按下
void mouseMoveEvent(QMouseEvent *e) override;        //移动
void mouseReleaseEvent(QMouseEvent *e) override;     //松开
void mouseDoubleClickEvent(QMouseEvent *event) override;     //双击
  • 鼠标按下事件 (mousePressEvent):

    当用户按下鼠标按钮时触发。标志开始绘制

    // 按下
    void MyPainterWidget::mousePressEvent(QMouseEvent *e)
    {if (e->button() == Qt::LeftButton){if(!m_bStartDraw){pointList.clear();m_bStartDraw = true;}}   
    }
    
  • 鼠标移动事件 (mouseMoveEvent):

    当鼠标移动时触发,如果按下了鼠标按钮,则可以在绘图事件中进行绘制,并标志处于绘制时的鼠标移动状态

    // 移动
    void MyPainterWidget::mouseMoveEvent(QMouseEvent *e)
    {if(m_bStartDraw){movePoint = e->pos();this->update();// 先刷新再设为true, 防止第一点和(0,0)连在一块bMove = true;}
    }
    
  • 鼠标释放事件 (mouseReleaseEvent):

    当用户释放鼠标按钮时触发,将鼠标松开后的点需要添加到路径中

    // 松开
    void MyPainterWidget::mouseReleaseEvent(QMouseEvent *e)
    {if (e->button() == Qt::LeftButton){if (m_bStartDraw){// 鼠标松开后的点需要添加到路径中pointList.push_back(QPointF(e->x(), e->y()));bMove = false;this->update();}}
    }
    
  • 鼠标双击事件(mouseDoubleClickEvent):

    当用户双击鼠标时,结束绘制

    // 双击结束绘制
    void MyPainterWidget::mouseDoubleClickEvent(QMouseEvent *event)
    {endDraw();
    }void MyPainterWidget::endDraw()
    {m_bStartDraw = false;//需要把第一个点连起来pointList.push_back(pointList[0]);this->update();
    }
    
  • 绘图事件(paintEvent):

    QWidget 的派生类中重写 paintEvent 来实现自定义绘制逻辑

    void MyPainterWidget::paintEvent(QPaintEvent *)
    {QPainter painter(this);painter.setPen(QColor(255,0,0));QVector<QLineF> lines;for(int i = 0; i < pointList.size()-1; i++){QLineF line(QPointF(pointList[i].x(), pointList[i].y()), QPointF(pointList[i+1].x(), pointList[i+1].y()));lines.push_back(line);}//绘制鼠标移动状态if (m_bStartDraw){int size = pointList.size();if (bMove && size > 0){QLineF line(QPointF(pointList[pointList.size() - 1].x(), pointList[pointList.size() - 1].y()),movePoint);lines.push_back(line);}}painter.drawLines(lines);	//画多条线
    }
    

示例:

需要维护布尔变量来跟踪是否处于绘制模式与移动模式

MyPainterWidget.h

#ifndef GRAPHICSPAINTER_H
#define GRAPHICSPAINTER_H#include <QWidget>class MyPainterWidget : public QWidget
{Q_OBJECTpublic:explicit MyPainterWidget(QWidget *parent = nullptr);void endDraw();     //结束绘制void clearPath();   //清除路径protected:void paintEvent(QPaintEvent *) override;void mousePressEvent(QMouseEvent *e) override;       //按下void mouseMoveEvent(QMouseEvent *e) override;        //移动void mouseReleaseEvent(QMouseEvent *e) override;     //松开void mouseDoubleClickEvent(QMouseEvent *event) override;     //双击bool m_bStartDraw = false;    //是否已经开始左键点击,同时标识是否开始进行绘制bool bMove = false;           //是否处于绘制时的鼠标移动状态QVector<QPointF> pointList;QPointF movePoint;
};#endif // GRAPHICSPAINTER_H

MyPainterWidget.cpp

#include "MyPainterWidget.h"
#include <QPainter>
#include <QMouseEvent>MyPainterWidget::MyPainterWidget(QWidget *parent) : QWidget(parent)
{setMouseTracking(true);  //窗口启用鼠标捕获pointList.clear();
}void MyPainterWidget::paintEvent(QPaintEvent *)
{QPainter painter(this);painter.setPen(QColor(255,0,0));QVector<QLineF> lines;for(int i = 0; i < pointList.size()-1; i++){QLineF line(QPointF(pointList[i].x(), pointList[i].y()), QPointF(pointList[i+1].x(), pointList[i+1].y()));lines.push_back(line);}if (m_bStartDraw){int size = pointList.size();if (bMove && size > 0){QLineF line(QPointF(pointList[pointList.size() - 1].x(), pointList[pointList.size() - 1].y()),movePoint);lines.push_back(line);}}painter.drawLines(lines);
}// 按下
void MyPainterWidget::mousePressEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){if(!m_bStartDraw){pointList.clear();m_bStartDraw = true;}}   
}// 移动
void MyPainterWidget::mouseMoveEvent(QMouseEvent *e)
{if(m_bStartDraw){movePoint = e->pos();this->update();// 先刷新再设为true, 防止第一点和(0,0)连在一块bMove = true;}
}// 松开
void MyPainterWidget::mouseReleaseEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){if (m_bStartDraw){// 鼠标松开后的点需要添加到路径中pointList.push_back(QPointF(e->x(), e->y()));bMove = false;this->update();}}
}// 双击结束绘制
void MyPainterWidget::mouseDoubleClickEvent(QMouseEvent *event)
{endDraw();
}void MyPainterWidget::endDraw()
{m_bStartDraw = false;//需要把第一个点连起来pointList.push_back(pointList[0]);this->update();
}void MyPainterWidget::clearPath()
{pointList.clear();this->update();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QMenu>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();protected:// 右键菜单需要重写的类//处理窗口的右键点击事件,以弹出一个菜单void contextMenuEvent(QContextMenuEvent* event) override;private:Ui::MainWindow *ui;QMenu* m_pMenu;
};
#endif // MAINWINDOW_H

mainwindow.cpp

/*
使用方式
左键点击,移动鼠标开始绘制,双击左键结束绘制,或者右键点击结束绘制
*/#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMenu>
#include <QAction>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);m_pMenu = new QMenu(this);QAction* pAc1 = new QAction(QString::fromLocal8Bit("结束绘制"), this);pAc1->setShortcut(QKeySequence("Ctrl+E"));QAction* pAc2 = new QAction(QString::fromLocal8Bit("清除"), this);pAc2->setShortcut(QKeySequence("Ctrl+D"));// 这是个假动作,为了让菜单消失,且不影响绘制路径QAction* pAc3 = new QAction(QString::fromLocal8Bit("退出菜单"), this);m_pMenu->addAction(pAc1);m_pMenu->addAction(pAc2);m_pMenu->addAction(pAc3);m_pMenu->setStyleSheet("QMenu{font:18px;}");connect(pAc1, &QAction::triggered, [=] {ui->graphicsPainter->endDraw();});connect(pAc2, &QAction::triggered, [=] {ui->graphicsPainter->clearPath();});
}MainWindow::~MainWindow()
{delete ui;
}// 这段代码的作用是当用户在 MainWindow 中通过鼠标右键触发上下文菜单时,将一个已经创建好的菜单 m_pMenu 移动到鼠标当前的位置,并显示出来。
void MainWindow::contextMenuEvent(QContextMenuEvent* event)
{m_pMenu->move(cursor().pos());  //将菜单的位置设置为当前鼠标光标的位置m_pMenu->show();  //显示菜单
}

main.cpp

#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

运行结果

image-20240709192615096

四、Qt绘制带三角形箭头的窗口

  本案例:在点击按钮时,弹出带三角形箭头的窗口(含窗口阴影)。

  • QPainterPath组合绘制

    // 小三角区域,这里是等腰三角形
    QPolygon trianglePolygon;
    trianglePolygon << QPoint(m_startX, m_triangleHeight + SHADOW_WIDTH);
    trianglePolygon << QPoint(m_startX + m_triangleWidth / 2, SHADOW_WIDTH);
    trianglePolygon << QPoint(m_startX + m_triangleWidth, m_triangleHeight + SHADOW_WIDTH);QPainterPath drawPath;
    drawPath.addRoundedRect(QRect(SHADOW_WIDTH, SHADOW_WIDTH + m_triangleHeight,this->width() - SHADOW_WIDTH * 2, this->height() - SHADOW_WIDTH * 2 - 								m_triangleHeight),BORDER_RADIUS, BORDER_RADIUS);
    // 矩形路径加上三角形
    drawPath.addPolygon(trianglePolygon);// 绘制路径
    painter.drawPath(drawPath);
    

示例:

  首先,绘制顶层窗口

userinfowidget.h

#ifndef USERINFOWIDGET_H
#define USERINFOWIDGET_H#include <QWidget>namespace Ui {
class UserInfoWidget;
}class UserInfoWidget : public QWidget
{Q_OBJECTpublic:explicit UserInfoWidget(QWidget *parent = nullptr);~UserInfoWidget();private:Ui::UserInfoWidget *ui;
};#endif // USERINFOWIDGET_H

userinfowidget.cpp

#include "userinfowidget.h"
#include "ui_userinfowidget.h"UserInfoWidget::UserInfoWidget(QWidget *parent) :QWidget(parent),ui(new Ui::UserInfoWidget)
{ui->setupUi(this);setFixedSize(this->width(), this->height());setAttribute(Qt::WA_StyledBackground);QString qss = "QLabel{font-family:Microsoft YaHei; font-size:18px; color:#ffffff; background-color:#363636;}";ui->label_UserImage->setText("");QPixmap pmp1(":/resources/user_image.png");pmp1.scaled(ui->label_UserImage->size(), Qt::KeepAspectRatio);ui->label_UserImage->setScaledContents(true);ui->label_UserImage->setPixmap(pmp1);ui->label_UserName->setText(u8"没有做完的梦最痛");ui->label_UserName->setStyleSheet(qss);ui->label_VipInfo->setText("");QPixmap pmp2(":/resources/vipinfo.png");pmp2.scaled(ui->label_VipInfo->size(), Qt::KeepAspectRatio);ui->label_VipInfo->setScaledContents(true);ui->label_VipInfo->setPixmap(pmp2);
}UserInfoWidget::~UserInfoWidget()
{delete ui;
}

  接着,绘制带三角的窗口(含窗口阴影)

triangledialog.h

/*带三角形箭头的对话框*/#ifndef TRIANGLEDIALOG_H
#define TRIANGLEDIALOG_H#include <QDialog>class TriangleDialog : public QDialog
{Q_OBJECT
public:explicit TriangleDialog(int fixedW, int fixedH, QWidget *parent = nullptr);// 设置小三角行的起始位置、宽、高void setTriangleInfo(int startX, int width, int height);protected:void paintEvent(QPaintEvent *e);private:// 小三角形的起始位置int m_startX;// 小三角形的宽度int m_triangleWidth;// 小三角形的高度int m_triangleHeight;
};#endif // TRIANGLEDIALOG_H

triangledialog.cpp

#include "triangledialog.h"
#include <QVBoxLayout>
#include <QPainter>
#include <QGraphicsDropShadowEffect>
#include <QPainterPath>
#include "userinfowidget.h"#define SHADOW_WIDTH    15                 // 窗口阴影宽度
#define TRIANGLE_WIDTH  15                 // 小三角行的宽度
#define TRIANGLE_HEIGHT 10                 // 小三角行的高度
#define BORDER_RADIUS   5                  // 窗口圆角TriangleDialog::TriangleDialog(int fixedW, int fixedH, QWidget *parent) : QDialog(parent),m_startX(50),m_triangleWidth(TRIANGLE_WIDTH),m_triangleHeight(TRIANGLE_HEIGHT)
{setWindowFlags(Qt::FramelessWindowHint | Qt::Popup | Qt::NoDropShadowWindowHint);setAttribute(Qt::WA_TranslucentBackground);  // 设置透明窗口, 为窗口阴影和圆角做准备UserInfoWidget* pUserinfoWidget = new UserInfoWidget(this);QVBoxLayout* pVlay = new QVBoxLayout(this);pVlay->addWidget(pUserinfoWidget);//设置布局的四周边距pVlay->setContentsMargins(SHADOW_WIDTH, SHADOW_WIDTH + TRIANGLE_HEIGHT, SHADOW_WIDTH, SHADOW_WIDTH);// 设置阴影边框auto shadowEffect = new QGraphicsDropShadowEffect(this);shadowEffect->setOffset(0, 0);shadowEffect->setColor(Qt::red);shadowEffect->setBlurRadius(SHADOW_WIDTH);this->setGraphicsEffect(shadowEffect);//设置窗口固定大小setFixedSize(fixedW, fixedH);
}void TriangleDialog::setTriangleInfo(int startX, int width, int height)
{m_startX = startX;m_triangleWidth = width;m_triangleHeight = height;
}void TriangleDialog::paintEvent(QPaintEvent *e)
{QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);painter.setPen(Qt::NoPen);painter.setBrush(QColor(55, 55, 55));// 小三角区域,这里是等腰三角形QPolygon trianglePolygon;trianglePolygon << QPoint(m_startX, m_triangleHeight + SHADOW_WIDTH);trianglePolygon << QPoint(m_startX + m_triangleWidth / 2, SHADOW_WIDTH);trianglePolygon << QPoint(m_startX + m_triangleWidth, m_triangleHeight + SHADOW_WIDTH);QPainterPath drawPath;drawPath.addRoundedRect(QRect(SHADOW_WIDTH, SHADOW_WIDTH + m_triangleHeight,this->width() - SHADOW_WIDTH * 2, this->height() - SHADOW_WIDTH * 2 - m_triangleHeight),BORDER_RADIUS, BORDER_RADIUS);// 矩形路径加上三角形drawPath.addPolygon(trianglePolygon);// 绘制路径painter.drawPath(drawPath);
}

  然后,调用 show() 方法会触发 paintEvent 来绘制窗口。

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void on_pushButton_clicked();private:Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include "triangledialog.h"
#include <QLabel>
#include "userinfowidget.h"
#include <QPropertyAnimation>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{int triangle_start_x = 60;TriangleDialog *pDialog = new TriangleDialog(343, 320, this);pDialog->setTriangleInfo(triangle_start_x, 20, 12);// 设置三角窗口的弹出位置, 有Qt::Popup属性QPoint p1 = ui->pushButton->mapToGlobal(QPoint(0, 0));  //按钮左上角相对于桌面的绝对位置QRect rect1 = ui->pushButton->rect();int x = p1.x() + rect1.width() / 2 - triangle_start_x - 20 / 2;int y = p1.y() + rect1.height() + 1 - 15;pDialog->move(x, y);pDialog->show();
}

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

运行结果

image-20240709203859903

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/376381.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

系统架构师考点--软件工程(上)

大家好。今天我来总结一下软件工程的相关考点。这部分是考试的重点。在上午场客观题、下午场案例题以及下午场论文都有可能考到&#xff0c;在上午场客观题中大约占12-15分左右。 一、软件工程概述 软件开发生命周期 软件定义时期&#xff1a;包括可行性研究和详细需求分析过…

单元测试实施最佳方案(背景、实施、覆盖率统计)

1. 什么是单元测试&#xff1f; 对于很多开发人员来说&#xff0c;单元测试一定不陌生 单元测试是白盒测试的一种形式&#xff0c;它的目标是测试软件的最小单元——函数、方法或类。单元测试的主要目的是验证代码的正确性&#xff0c;以确保每个单元按照预期执行。单元测试通…

构建高精度室内定位导航系统,从3DGIS到AI路径规划的全面解析

室内定位导航系统是一种利用多种技术实现室内精准定位和导航的智能系统&#xff0c;即便没有卫星信号&#xff0c;也能实现精准导航。维小帮室内定位导航系统是基于自研的地图引擎与先进定位技术&#xff0c;结合智能路径规划算法&#xff0c;解决了人们在大型复杂室内场所最后…

【Linux】多线程_3

文章目录 九、多线程3. C11中的多线程4. 线程的简单封装 未完待续 九、多线程 3. C11中的多线程 Linux中是根据多线程库来实现多线程的&#xff0c;C11也有自己的多线程&#xff0c;那它的多线程又是怎样的&#xff1f;我们来使用一些C11的多线程。 Makefile&#xff1a; te…

Unity基础调色

叭叭叭 最近&#xff08;*这两天&#xff09;因为想做一些Unity的调色问题&#xff0c;尝试原文翻译一下&#xff0c;其实直接原文更好&#xff01;&#xff01; Color Grading 参考了&#xff0c;某大牛的翻译&#xff0c;实在忍不住了&#xff0c;我是不知道为什么能翻译成…

Vivado 2020.1 HLS IP在BD模式无法生成问题

折腾了一周整整&#xff0c;记录一下&#xff0c;希望对大家有用。 各种找、各种操作&#xff0c;也问了FAE&#xff0c;都没搞定。 最后看到如下博文的方法3&#xff0c;管用。 vivado综合hls类ip核报错问题解决方案_vivado ip synth checkpoint mode-CSDN博客 报错描述 m…

论文翻译:Large Language Models for Education: A Survey and Outlook

https://arxiv.org/abs/2403.18105 目录 教育领域的大型语言模型&#xff1a;一项调查和展望摘要1. 引言2. 教育应用中的LLM2.1 概述2.2 学习辅助2.2.1 问题解决&#xff08;QS&#xff09; 2.2.2 错误纠正&#xff08;EC&#xff09;2.2.3 困惑助手&#xff08;CH&#xff09;…

Jenkins中Node节点与构建任务

目录 节点在 Jenkins 中的主要作用 1. 分布式构建 分布式处理 负载均衡 2. 提供不同的运行环境 多平台支持 特殊环境需求 3. 提高资源利用率 动态资源管理 云端集成 4. 提供隔离和安全性 任务隔离 权限控制 5. 提高可扩展性 横向扩展 高可用性 Jenkins 主服务…

【香菇带你学Linux】Linux环境下gcc编译安装【建议收藏】

文章目录 0. 前言1. 安装前准备工作1.1 创建weihu用户1.2 安装依赖包1.2.1 安装 GMP1.2.2 安装MPFR1.2.3 安装MPC 2. gcc10.0.1版本安装3. 报错解决3. 1. wget下载报错 4. 参考文档 0. 前言 gcc&#xff08;GNU Compiler Collection&#xff09;是GNU项目的一部分&#xff0c;…

excel 百分位函数 学习

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、函数说明PERCENTILE 函数PERCENTILE.inc 函数PERCENTILE.exc 函数QUARTILE.EXC 函数 二、使用步骤总结 前言 excel 百分位函数 Excel提供了几个函数用于…

ctfshow-web入门-php特性(web100-web103)is_numeric 函数绕过

目录 1、web100 2、web101 3、web102 4、web103 1、web100 提示&#xff1a;flag in class ctfshow&#xff0c;我们只需要构造输出 ctfshow 这个类即可。 代码分析&#xff1a; $v0is_numeric($v1) and is_numeric($v2) and is_numeric($v3); if($v0){ 虽然逻辑运算符的…

Spring Boot整合Druid:轻松实现SQL监控和数据库密码加密

文章目录 1 引言1.1 简介1.2 Druid的功能1.3 竞品对比 2 准备工作2.1 项目环境 3 集成Druid3.1 添加依赖3.2 配置Druid3.3 编写测试类测试3.4 访问控制台3.5 测试SQL监控3.6 数据库密码加密3.6.1 执行命令加密数据库密码3.6.2 配置参数3.6.3 测试 4 总结 1 引言 1.1 简介 Dru…

gfast前端UI:基于Vue3与vue-next-admin适配手机、平板、pc 的后台开源模板

摘要 随着现代软件开发的高效化需求&#xff0c;一个能够快速适应不同设备、简化开发过程的前端模板变得至关重要。gfast前端UI&#xff0c;基于Vue3.x和vue-next-admin&#xff0c;致力于提供这样一个解决方案。本文将深入探讨gfast前端UI的技术栈、设计原则以及它如何适配手机…

Neo4j:图数据库的革命性力量

Neo4j 首席技术官 prathle 撰写了一篇出色的博文&#xff0c;总结最近围绕 GraphRAG 的热议、我们从一年来帮助用户使用知识图谱 LLM 构建系统中学到的东西&#xff0c;以及我们认为该领域的发展方向。Neo4j一时间又大火起来&#xff0c;本文将带你快速入门这神奇的数据库。 前…

sentinel源码分析: dashboard与微服务的交互、pull模式持久化

文章目录 原始方式微服务端规则如何保存规则如何加载进内存微服务端接收控制台请求控制台推送规则总结 pull拉模式官方demo如何整合Spring Cloud整合Spring Cloud 前置知识 SentinelResource的实现原理、SphU.entry()方法中ProcessorSlotChain链、entry.exit() 建议先会使用se…

秋招Java后端开发冲刺——MyBatisPlus总结

一、 基本知识 1. 介绍 yBatis-Plus 是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上增加了大量功能和简化操作&#xff0c;以提高开发效率。 2. 特点 无侵入&#xff1a;只做增强不做改变&#xff0c;引入它不会对现有项目产生影响。依赖少&#xff1a;仅仅依赖 …

谈谈软件交互设计

谈谈软件交互设计 交互设计的由来 交互设计(Interaction Design)这一概念,最初是由IDEO创始人之一Bill.Moggridge(莫格里奇)1984年在一次会议上提出。他设计了世界上第一台笔记本电脑Compass,并写作出版了在交互设计领域影响深远的《Designing Interactions》一书,被称…

mqtt.fx连接阿里云

本文主要是记述一下如何使用mqtt.fx连接在阿里云上创建好的MQTT服务。 1 根据MQTT填写对应端口即可 找到设备信息&#xff0c;里面有MQTT连接参数 2 使用物模型通信Topic&#xff0c;注意这里的post说设备上报&#xff0c;那也就是意味着云端订阅post&#xff1b;set则意味着设…

Linux内核编译安装 - Deepin,Debian系

为什么要自己编译内核 优点 定制化&#xff1a;你可以根据自己的硬件和需求配置内核&#xff0c;去掉不必要的模块&#xff0c;优化性能。性能优化&#xff1a;移除不需要的驱动程序和特性&#xff0c;减小内核体积&#xff0c;提高系统性能。最新特性和修复&#xff1a;获取…

【密码学】从有限状态自动机到密钥流生成器

本文是对流密码内容的拓展&#xff0c;在流密码中种子密钥通过一个伪随机数生成器产生一个与明文等长的伪随机密钥流。而本文的内容就是在回答这样两个问题&#xff1a; 伪随机密钥流是如何生成的&#xff1f;流密码、流密钥生成器和有限状态自动机之间是什么关系&#xff1f;…