当前位置: 首页 > news >正文

QT传输函数控件设计9 初步设计视口类

我们先按照之前的布局设计中,先把 TsfunDockWidget 以及 TsfunWidget 对象设计完。注意 DockWidget 里的中心窗体设置。然后定义继承自QWidget的类TsfunWidget类以及继承自QGraphicsView类的TsfunView类,并把这个类实例化加到TsfunWidget类里面,为了玩玩布局我们也可以在TsfunWidget的布局里再加个按键(没啥用,就是添加个东西而已)。

然后现在先写一下我们的类的基本框架

#ifndef __TransferfunctionView_H__
#define __TransferfunctionView_H__

#include <QGraphicsView>
#include <QMouseEvent>
#include "margin.hpp"


class TsfunView : public QGraphicsView{
	Q_OBJECT

public:
	TsfunView(QGraphicsView * parent = Q_NULLPTR);
	~TsfunView();

	Margin viewMargin;

private:
	void mousePressEvent(QMouseEvent * event);
	void mouseReleaseEvent(QMouseEvent * pEvent);
	void resizeEvent(QResizeEvent* MyResizeEvent);
	
};


#endif

目前只是在里面定义了一个Margin区域而已。然后我们进行初始化:

TsfunView::TsfunView(QGraphicsView * parent) : QGraphicsView(parent) ,
viewMargin(0, 0, 0, 150),
selectedItemFlags(0),
moveForFlags(0)
{
	setMinimumHeight(150);
	setMinimumWidth(300);	

	scene = new QGraphicsScene;
	scene->setBackgroundBrush(QColor(225,255,255,255));
	setScene(scene);
	setRenderHint(QPainter::Antialiasing);
	//任何时候都不使用滚轮
	setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);



}

TsfunView::~TsfunView() {
	
}

我们设置了区域的边界,注意这里的第四个参数150,表示前面所说的bottom+remained区域的大小,然后设置了View的最小大小,然后在里面定义一个场景,并设置显示为 Antialiasing ,抗锯齿效果。然后设置任何时候都不用滚轮。其他函数目前还没有要写的东西。先把函数简单创建完就行了。

接下来我们考虑:要在场景里放些什么东西呢?

1. 首先我们要定义一个矩形图形项类,用它来画坐标轴。

2. 然后我们再定义一个矩形图形项类,用它来画小圆点。每次update都要把所有点都画一次。

首先我们要放置的东西也就这俩。那么我们现在就根据Margin来定义一下画坐标轴的矩形类:

#pragma once
#ifndef __TsfFunGrid_H__
#define __TsfFunGrid_H__

#include <QGraphicsRectItem>
#include "margin.hpp"
class TsfunGridItem : public QGraphicsRectItem {

public:
	TsfunGridItem(QGraphicsRectItem * parent = Q_NULLPTR);
	~TsfunGridItem();

	void setGridHeight(int height) {
		gridHeight = height;
	}
	void setGridWidth(int width) {
		gridWidth = width;
	}
	void setDataWidth(int width) {
		dataWidth = width;
	}
	Margin gridMargin;
	
	void calculate();
	int returnTopBoundary() {
		return lineHeightStart;
	}
	int returnLeftBoundary() {
		return lineWidthStart;
	}
	int returnRightBoundary() {
		return lineWidthEnd;
	}
	int returnBottomBoundary() {
		return lineHeightEnd;
	}

	int lineWidthStart;
	int lineWidthEnd;
	int lineHeightStart;
	int lineHeightEnd;
private:
	int gridHeight;
	int gridWidth;

	int dataWidth;
	int segment;
	int gridXNums;//x方向上的段数
	int gridYNums;//y方向上的段数
	int segmentHeight;//段高 像素数
	int segmentWidth;//段宽 像素数
	int remainLength;//剩余的长度(像素)

	void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);

};

#endif

我们来一 一分析一下里面所有的变量的作用:

首先是 Margin gridMargin; 表示我们期望的中间的绿框的区域距离各个边界的距离。注意一点:这只是我们的期望,因为我们的坐标值是离散的,而且数据的范围(比如-1000——3000)都在变,总不可能我们用横排的4000个值来表示这4000个坐标吧?所以我们只能先根据期望的绿框区域计算出距离显示数据范围最近的值,然后重新分配坐标。

void TsfunGridItem::calculate() {
	//注意这里的Margin是给画线区设置的。
	//数据400个为一段
	gridXNums = dataWidth / segment;
	int gridXRemain = dataWidth % segment;
	double remainDot = (double)gridXRemain / (double)segment;
	double segmentDot = gridXNums + remainDot;
	lineWidthStart = gridMargin.leftToBoundary();//-2
	int lineWidthLength = gridWidth - gridMargin.leftToBoundary() - gridMargin.rightToBoundary();
	segmentWidth = lineWidthLength / segmentDot;
	remainLength = segmentWidth*remainDot;
	lineWidthEnd = gridMargin.leftToBoundary() + gridXNums*segmentWidth + remainLength;

	gridYNums = 10;
	int lineHeightLength = gridHeight - gridMargin.topToBoundary() - gridMargin.bottomToBoundary();
	segmentHeight = lineHeightLength / gridYNums;
	lineHeightStart = gridMargin.topToBoundary();
	lineHeightEnd = gridMargin.topToBoundary() + segmentHeight*gridYNums;
}

所以我们定义了dataWidth,表示数据宽度,假设这里是4024。然后我们定义了segment表示每段数据量(比如400个数据表示在一个格子里。)然后我们定义了gridXNums表示x方向上的段数,即4024/400的值,但是因为没有除尽,所以还有一个remainDot,表示的是小数上剩余的长度占每一段长度的比例。以及segmentDot用小数表示一共多少段,画线中,从左到右的起始点我们设置为lineWidthStart,线长lineWidthLength(理论长度)是用格子长度除以小数表示的段数,然后从lineWidthStart进行累加,得到终点。

高度求法也一样。通过求值,我们最后得出lineWidthStart画线横轴起点,lineWidthEnd画线横轴终点,lineHeightStart画线纵轴起点,注意纵轴因为直接是用百分之0显示到百分之100,所以不需要dataWidth表示数据宽度,gridYNums直接设置为10就好了。

然后我们在

void TsfunGridItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
{
	painter->setPen(QPen(QColor(0,25,25,100)));


	int i = 0;
	for (i = 0;i<=gridYNums;i++) {
		painter->drawLine(lineWidthStart-2, lineHeightStart+i*segmentHeight,
			lineWidthEnd, lineHeightStart + i*segmentHeight);
	}
	for (i = 0;i<gridXNums;i++) {
		painter->drawLine(lineWidthStart + i*segmentWidth, lineHeightStart,
			lineWidthStart + i*segmentWidth, lineHeightEnd);
	}painter->drawLine(lineWidthStart + i*segmentWidth + remainLength, lineHeightStart,
		lineWidthStart + i*segmentWidth + remainLength, lineHeightEnd);
	//关于点和坐标对应关系: 点只记录实际坐标(单位化的)。 坐标轴上每个点都映射到坐标里。


	//DebugText::getDebugText()->addContents("lalala1");
}

这个函数里根据我们生成的值来画点,为了左边的横线多处一点来,我们在这里设置了lineWidthStart-2作为起始点。

之后我们把该图形项添加到View构造函数里面,添加到场景中去,然后在resizeEvent函数里添加:

        int sceneForGridWidth;
	setSceneRect(0, 0, width(), height() - 2);
	//scene->clear();
	dataGrid->setGridHeight(height()-2 - viewMargin.bottomToBoundary());
	dataGrid->setGridWidth(width());
	dataGrid->calculate();
	dataGrid->setRect(0,0,width(), height()-2- viewMargin.bottomToBoundary());

注意这里的height() - 2,因为如果直接setSceneRect(0, 0, width(), height() );你会发现虽然没有滚轮但是还是可以上下滚动,可能是QT的Bug,大概就是高度正好多了2,所以这里减去就好了。因为我们的坐标基本上都是根据View来的,所以其实这里就算不设置也无所谓。

现在,你的坐标系已经可以根据你拉扯边框来改变大小了。下一节我们再讨论把小圆点添加进去。

相关文章:

  • QT传输函数控件设计10 包含小圆点的图形项
  • QT传输函数控件设计11 包含小圆点的图形项2
  • QT传输函数控件设计12 自定义信号和槽
  • QT传输函数控件设计13 大结局
  • QT三维图形1
  • QT三维图形2
  • QT三维图形3
  • QT三维图形4
  • icache的方面以及使用
  • cmp bne 以及sub指令的详解
  • 关于ARM Cortex a 系列的看门狗定时器
  • C语言之 认识可变参数
  • ARM cortex a 的SDRAM (DDR)
  • C语言 之递归函数
  • C语言 之建立静态链接库
  • [译] 怎样写一个基础的编译器
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • Angular4 模板式表单用法以及验证
  • bearychat的java client
  • iOS编译提示和导航提示
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • JDK9: 集成 Jshell 和 Maven 项目.
  • Laravel 菜鸟晋级之路
  • Objective-C 中关联引用的概念
  • OSS Web直传 (文件图片)
  • Python利用正则抓取网页内容保存到本地
  • 记录一下第一次使用npm
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 使用parted解决大于2T的磁盘分区
  • Hibernate主键生成策略及选择
  • mysql面试题分组并合并列
  • python最赚钱的4个方向,你最心动的是哪个?
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • #图像处理
  • $.ajax()方法详解
  • ( 10 )MySQL中的外键
  • (06)金属布线——为半导体注入生命的连接
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (2)Java 简介
  • (42)STM32——LCD显示屏实验笔记
  • (多级缓存)多级缓存
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .NET4.0并行计算技术基础(1)
  • .net实现客户区延伸至至非客户区
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • .py文件应该怎样打开?
  • @RequestMapping 的作用是什么?
  • [CF226E]Noble Knight's Path
  • [GXYCTF2019]BabyUpload1 -- 题目分析与详解
  • [js]js设计模式小结