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.mzph.cn/news/869465.shtml

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

相关文章

如何在 C 语言中实现链表?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; &#x1f4d9;C 语言百万年薪修炼课程 通俗易懂&#xff0c;深入浅出&#xff0c;匠心打磨&#xff0c;死磕细节&#xff0c;6年迭代&#xff0c;看过的人都说好。 文章目…

vue子组件调用父组件方法

父组件 页面<popoverss ref"pop" :goodspop"goodspop"></popoverss>子组件components: {"popoverss": () > import(../comm/popover.vue)},方法goodspop(e){console.log(e"----")return 9999;},子组件 方法props:[go…

习题练习以

题意&#xff1a;求i&M的popcount的和&#xff0c;i属于0……N 主要思路还是变加为乘。 举个例子N22&#xff0c;即10110 假设M的第3位是1&#xff0c;分析N中&#xff1a; 00110 00111 00100 00101 发现其实等价于 0010 0011 0000 0001 也就是左边第4位和第5…

《AIGC:智能创作时代》:AI创作革命来临,你准备好了吗?

想象一下&#xff0c;你正在欣赏一幅精美的画作&#xff0c;惊叹于其细腻的笔触和独特的构图。然而&#xff0c;当你得知这幅作品是由人工智能创作时&#xff0c;你会作何感想&#xff1f;这不再是科幻小说中的场景&#xff0c;而是我们正在经历的现实。 在这个AI技术飞速发展的…

QListWidget、QTreeWidget、QTableWidget的拖放

QListWidget、QTreeWidget、QTableWidget的拖放实验 QAbstractItemView::DragDropMode 的枚举值 QAbstractItemView::NoDragDrop0组件不支持拖放操作QAbstractItemView::DragOnly1组件只支持拖动操作QAbstractItemView::DropOnly 2组件只支持放置操作QAbstractItemView::DragDr…

AI 图像处理 --CodeFormer 简介

CodeFormer是一款基于深度学习技术&#xff0c;特别是利用自动编码器和VQGAN&#xff08;Vector Quantised Generative Adversarial Network&#xff09;进行人脸修复和视频增强的强大人工智能工具。它通过高分辨率重建和细节修复&#xff0c;显著提升了图像和视频的质量和视觉…

Django 视图 - FBV 与 CBV

Django 视图 - FBV 与 CBV 在 Django 框架中,视图是处理 Web 请求和返回 Web 响应的核心组件。Django 提供了两种主要的视图编写方式:函数基础视图(Function-Based Views,简称 FBV)和类基础视图(Class-Based Views,简称 CBV)。这两种方式各有特点,适用于不同的场景。…

WPF设置全局样式

目的 创建一个资源字典&#xff0c;自动引入到各个Window或者UserControl中&#xff0c;可以随意使用。或者引入多个控件包&#xff0c;为了做兼容&#xff0c;保证可以引用多个控件库。 1. 定义资源字典 首先&#xff0c;你需要创建一个XAML文件来定义你的资源字典&#xf…

Python中JSON处理技术的详解

引言 JSON&#xff08;JavaScript Object Notation&#xff09;作为当前最流行的数据传输格式&#xff0c;在Python中也有多种实现方式。由于JSON的跨平台性和简便易用性&#xff0c;它在数据交互中被广泛应用。本文将重点讨论如何熟练应用Python的JSON库&#xff0c;将JSON数…

生日判断星座【GO】

文章目录 星座列表生日转换为星座 星座列表 const (Aries "aries"Taurus "taurus"Gemini "gemini"Cancer "cancer"Leo "leo"Virgo "virgo"Libra "libra&q…

小红书后端

牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推&#xff0c;求职就业一站解决_牛客网 (nowcoder.com) 小红书推荐系统 题目&#xff1a; 思路&#xff1a; 尝试&#xff08;标题4&#xff09; import java.util.*;// 注意类名必须为 Main, 不要有任何 package xxx 信息…

FFmpeg 实现从麦克风获取流并通过RTMP推流

使用FFmpeg库实现从麦克风获取流并通过RTMP推流&#xff0c;FFmpeg版本为4.4.2-0。RTMP服务器使用的是SRS&#xff0c;我这边是跑在Ubuntu上的&#xff0c;最好是关闭掉系统防火墙。拉流端使用VLC。如果想要降低延时&#xff0c;请看我另外一篇博客&#xff0c;里面有说降低延时…

github 下载提速的几种方法

1. 代理下载&#xff08;无需注册&#xff09; //toolwa.com/github/ //d.serctl.com/2. 转入 Gitee 加速 将项目镜像到 Gitee 中下载加速 3. 使用 Watt Toolkit 加速 Watt Toolkit //steampp.net/选择合适的版本下载 选择 github&#xff0c;一键加速 4.CDN 加速 (修改…

html转markdown nodejs实现

用到了jsdom库&#xff0c;直接现成处理html标签结构&#xff0c;只需要关心format格式化样式即可。 比较简易&#xff0c;待后续优化&#xff0c;目前只是短时间批量转换html文件。 const { JSDOM } require(jsdom);const getText (htmlString) > {if (!htmlString) re…

浏览器开发者视角及CSS表达式选择元素

点击想要查看的接口&#xff0c;然后点击检查&#xff0c;便可以切换到该接口对应的html代码 如果F12不起作用的话&#xff0c;点击更多工具&#xff0c;然后选择开发者工具即可 ctrlF可以去查阅相关的CSS表达式选择元素 如果没有加#t1&#xff0c;那么表示的是选择所有的p 使用…

图解HTTP(5、与 HTTP 协作的 Web 服务器 6、HTTP 首部)

5、与 HTTP 协作的 Web 服务器 一台 Web 服务器可搭建多个独立域名的 Web 网站&#xff0c;也可作为通信路径上的中转服务器提升传输效率。 用单台虚拟主机实现多个域名 在相同的 IP 地址下&#xff0c;由于虚拟主机可以寄存多个不同主机名和域名的 Web 网站&#xff0c;因此…

Linux-多线程

线程的概念 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列”一切进程至少都有一个执行线程线程在进程内部运行&#xff0c;本质是在进程地址空间内运行在Linux系统中&#xff0c;在CPU眼中…

Labview_压缩文件

调用顺序 源文件 生成后的文件 1.新建ZIP文件 生成ZIP文件的路径&#xff1a;为最终生成ZIP文件的路径&#xff0c;需要提供ZIP文件的名称和类型 2.添加文件到压缩文件 源文件路径&#xff1a;为需要压缩的文件路径&#xff0c;非文件夹路径 生成ZIP文件时的路径&#x…

Elasticsearch 缓存策略详解:优化你的搜索体验

目录 1. Elasticsearch缓存机制概述 2. 缓存机制的详细解析 2.1 节点查询缓存 2.2 分片请求缓存 2.3 字段数据缓存 2.4 分片查询缓存 3. 合理缓存比例设置 3.1 节点查询缓存 3.2 分片请求缓存 3.3 字段数据缓存 3.4 分片查询缓存 4. 缓存监控与调优 5.实战调优 5…

区域特征检测工具的使用

区域特征检测工具的使用 选择区域-》右键-》工具->特征检测