一个Python GUI……

嘛……实验室要用所以写的,存档一下……实验上还有些问题所以以后还会有所修改

Painter.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'E:\实验室\FCController\Qt_Designer\DrawPoints.ui'
#
# Created by: PyQt5 UI code generator 5.12
#
# WARNING! All changes made in this file will be lost!

import sys
import os
from PyQt5.QtCore import QRect, Qt
from PyQt5.QtGui import QIcon, QFont, QPainter, QPen, QColor
from PyQt5.QtWidgets import QWidget, QPushButton, QLineEdit, QLabel, QMessageBox, QFileDialog, QApplication

sys.path.append('.')
import savepoint as PtoCSV
import basepaint

class ParaError(Exception):
    def __init__(self, ErrorInfo):
        super().__init__(self)
        self.errorinfo=ErrorInfo
    def __str__(self):
        return self.errorinfo

class Popup(QWidget):
    def __init__(self, func, parent_window, para_list):
        QWidget.__init__(self)
        self.setWindowOpacity(0.9)
        self.process = func
        self.pw = parent_window
        self.setWindowTitle("Parameters")
        self.setWindowIcon(QIcon("mspaint.ico"))
        self.para_num = len(para_list)

        self.Button = QPushButton("Draw!", self)
        self.Button.setGeometry(QRect(20+self.para_num*120, 20, 60, 70))
        self.Button.setFont(QFont("Microsoft YaHei"))
        self.Button.clicked.connect(self.run_func)

        self.para = []
        self.label = []
        for i in range(self.para_num):
            # 参数输入框
            self.para.append(QLineEdit(self))
            self.para[i].setGeometry(QRect(20+i*120, 50, 100, 40))
            # 参数描述
            self.label.append(QLabel(self))
            self.label[i].setGeometry(QRect(20+i*120, 20, 100, 40))
            self.label[i].setAlignment(Qt.AlignHCenter)
            self.label[i].setText(para_list[i])
            self.label[i].setFont(QFont("Microsoft YaHei"))

    def run_func(self, event):
        try:
            para = []
            for i in range(self.para_num):
                para.append(int(self.para[i].text()))
                if(para[i] <= 0):
                    raise ParaError("Invalid Parameters!")
            self.pw.Image = self.process(self.pw.Image, self.pw.nx, self.pw.ny, para)
            self.close()
        except Exception as e:
            #self.setWindowTitle("Parameters - "+str(e))
            QMessageBox.critical(self, "Invalid Parameters!", str(e),)

class SimpleDrawingBoard(QWidget):
    def __init__(self):
        super(SimpleDrawingBoard, self).__init__()

        Width = 1100
        Height = 970

        self.update_pic_range(BackgroudStartX=100, BackgroudEndX=1028, \
            BackgroudStartY=20, BackgroudEndY=948, Divider=32)

        #是否允许拖曳绘制,默认打开
        self.EnableDragDraw = True

        #resize设置宽高,move设置位置
        self.resize(Width, Height)
        self.move(100, 10)
        self.setWindowTitle("DrawPoint")
        self.setWindowIcon(QIcon("mspaint.ico"))

        #保存按钮
        self.SaveButton = QPushButton("Save", self)
        self.SaveButton.setGeometry(QRect(10, 20, 80, 40))
        self.SaveButton.clicked.connect(self.isSaveButtonClicked)
        self.SaveButton.setFont(QFont("Microsoft YaHei"))
        #清除按钮
        self.CleanButton = QPushButton("Clean", self)
        self.CleanButton.setGeometry(QRect(10, self.YE-40, 80, 40))
        self.CleanButton.clicked.connect(self.isCleanButtonClicked)
        self.CleanButton.setFont(QFont("Microsoft YaHei"))
        #增减按钮
        self.divider_double_button = QPushButton("+", self)
        self.divider_double_button.setGeometry(QRect(10, 80, 40, 40))
        self.divider_double_button.clicked.connect(self.double_grid)
        self.divider_half_button = QPushButton("-", self)
        self.divider_half_button.setGeometry(QRect(50, 80, 40, 40))
        self.divider_half_button.clicked.connect(self.half_grid)

        #几个常用图形按钮
        self.circle_button = QPushButton("Cirle", self)
        self.circle_button.setGeometry(QRect(10, 180, 80, 40))
        self.circle_button.clicked.connect(self.circlebutton_clicked)
        self.circle_button.setFont(QFont("Microsoft YaHei"))
        self.rect_button = QPushButton("Rect", self)
        self.rect_button.setGeometry(QRect(10, 280, 80, 40))
        self.rect_button.clicked.connect(self.rectbutton_clicked)
        self.rect_button.setFont(QFont("Microsoft YaHei"))
        self.ellipse_button = QPushButton("Ellipse", self)
        self.ellipse_button.setGeometry(QRect(10, 380, 80, 40))
        self.ellipse_button.clicked.connect(self.ellipsebutton_clicked)
        self.ellipse_button.setFont(QFont("Microsoft YaHei"))
        self.ellipse_button.setDisabled(True)

        self.setMouseTracking(True)

        #设置两个变量接收移动中的点的x、y坐标
        self.pos_x = 0
        self.pos_y = 0
        self.Current_pos_x = 0
        self.Current_pos_y = 0

    def OutRange(self):
        x = self.Current_pos_x
        y = self.Current_pos_y
        if(x>=self.XE or x<=self.XS or y>=self.YE or y<=self.YS):
            return True
        else:
            return False

    def update_pic_range(self, BackgroudStartX=100, BackgroudStartY=20, BackgroudEndX=1028, BackgroudEndY=948, Divider=16):
        BackgroudEndX = BackgroudStartX  + (BackgroudEndX-BackgroudStartX)//Divider*Divider
        BackgroudEndY = BackgroudStartY  + (BackgroudEndY-BackgroudStartY)//Divider*Divider

        self.XS = BackgroudStartX
        self.YS = BackgroudStartY
        self.XE = BackgroudEndX
        self.YE = BackgroudEndY
        self.Divider = Divider
        self.nx = (self.XE-self.XS)//self.Divider
        self.ny = (self.XE-self.XS)//self.Divider

        #初始化格子绘制情况
        self.Image = [[0]*self.ny for i in range(self.nx)]

        #设置初始背景格子绘点
        self.GridMatrix = []
        #横向线条
        for i in range(0, self.ny+1):
            self.GridMatrix.append((self.XS, self.YS+i*Divider, self.XE, self.YS+i*Divider))
        #纵向线条
        for i in range(0, self.nx+1):
            self.GridMatrix.append((self.XS+i*Divider, self.YS, self.XS+i*Divider, self.YE))

    def CurrentPos(self):
        return ((self.Current_pos_x-self.XS)//self.Divider, (self.Current_pos_y-self.YS)//self.Divider)

    def BackgroundPaint(self):
        '''
            绘制格子,将当前鼠标指向的格子染蓝,将点过的格子染红
        '''
        Matrix = self.GridMatrix
        painter = QPainter()
        painter.begin(self)
        pen = QPen(QColor(200,200,200), 1, Qt.SolidLine)
        painter.setPen(pen)
        painter.setBrush(QColor(100,149,237)) # #6495ED Cornflower blue

        # Draw the block that mouse is on.
        if not self.OutRange():
            mouseblock = self.CurrentPos()
            painter.drawRect(self.XS+mouseblock[0]*self.Divider, self.YS+mouseblock[1]*self.Divider, self.Divider, self.Divider)
        for i in range(0, len(Matrix)):
            points = Matrix[i] 
            painter.drawLine(points[0],points[1],points[2],points[3])

        # Draw Image
        painter.setBrush(QColor(255,0,0))
        for i in range(0,self.nx):
            for j in range(0,self.ny):
                if(self.Image[i][j]==1):
                    painter.drawRect(self.XS+i*self.Divider, self.YS+j*self.Divider, self.Divider, self.Divider)
        painter.end()

    def paintEvent(self, event):
        '''
            当事件触发更新绘图时候,调用BackgroundPaint方法绘制一次区域
        '''
        self.BackgroundPaint()

    def isSaveButtonClicked(self, event):
        '''
            按下保存按键
        '''
        filename, ok = QFileDialog.getSaveFileName(QApplication.desktop(), 'save points', os.getcwd(), '*.csv')
        if(ok):
            pointlist = PtoCSV.covert_pmatrix_to_csv(self.Image)
            PtoCSV.write_points_to_file(filename, pointlist, (self.nx, self.ny))
    def isCleanButtonClicked(self, event):
        '''
            按下清除按键
        '''
        self.Image = [[0]*((self.YE-self.YS)//self.Divider) for i in range(((self.XE-self.XS)//self.Divider))]
        self.update()
    def half_grid(self, event):
        if((self.nx==1) or (self.ny==1)):
            pass
        else: self.update_pic_range(Divider=self.Divider*2)
        self.update()
    def double_grid(self, event):
        if(self.Divider==4):
            pass
        else: self.update_pic_range(Divider=self.Divider//2)
        self.update()
    def circlebutton_clicked(self, event):
        self.parameter_window = Popup(basepaint.circle, self, ['r', 'theta/°', 'n'])
        self.parameter_window.move(200, 200)
        self.parameter_window.setFixedSize(100+120*3, 110)
        self.parameter_window.show()
    def rectbutton_clicked(self, event):
        self.parameter_window = Popup(basepaint.rect, self, ['na', 'nb', 'delta'])
        self.parameter_window.move(200, 200)
        self.parameter_window.setFixedSize(100+120*3, 110)
        self.parameter_window.show()
    def ellipsebutton_clicked(self, event):
        a = 10
        b = 5
        delta = 1
        self.Image = basepaint.ellipse(self.Image, self.nx, self.ny, a, b, delta)

    def mousePressEvent(self, event):
        '''
            点击鼠标事件
        '''
        # self.pos_x = event.pos().x()
        # self.pos_y = event.pos().y()
        if self.OutRange():
            return     
        if (event.buttons() == Qt.LeftButton):
            #左键点击,染色
            tmp = self.CurrentPos()
            self.Image[tmp[0]][tmp[1]] = 1
        if (event.buttons() == Qt.RightButton):
            #右键点击,取消染色
            tmp = self.CurrentPos()
            self.Image[tmp[0]][tmp[1]] = 0
        #print(self.Image)
        self.update() #重新绘制

    def mouseMoveEvent(self, event):
        '''
            鼠标移动事件
        '''
        self.Current_pos_x = event.pos().x()
        self.Current_pos_y = event.pos().y()
        if(self.OutRange()):
            PositionString = "x=NA y=NA"
        else:
            tmp = self.CurrentPos()
            tmp = (tmp[0]+1,tmp[1]+1)
            PositionString = "x=%d y=%d" % tmp
            if(self.EnableDragDraw):
                if (event.buttons() == Qt.LeftButton):
                    #左键点击,染色
                    #触摸板上容易误操作,仅保留连续取消染色
                    tmp = self.CurrentPos()
                    #self.Image[tmp[0]][tmp[1]] = 1
                if (event.buttons() == Qt.RightButton):
                    #右键点击,染色
                    tmp = self.CurrentPos()
                    self.Image[tmp[0]][tmp[1]] = 0
        self.setWindowTitle("DrawPoint : "+PositionString)
        self.update()
        #self.PositionLabel.setText("%d.%d" % (self.Current_pos_x, self.Current_pos_y))


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    MainWindow = SimpleDrawingBoard()
    MainWindow.show()
    sys.exit(app.exec_())

basepaint.py

#!/usr/bin/env python3
#coding=utf-8

import numpy as np
import os
import sys

def rect(img, nx, ny, parameters):
    na, nb, delta = parameters
    draw = np.zeros((nx,ny), dtype=np.int)
    center_x = nx//2
    center_y = ny//2
    for i in range(na):
        for j in range(nb):
            if((center_x+i*delta >= nx) or (center_y+i*delta >= ny)):
                continue
            else:
                draw[center_x+i*delta][center_y+j*delta]=1
                draw[center_x+i*delta][center_y-j*delta]=1
                draw[center_x-i*delta][center_y+j*delta]=1
                draw[center_x-i*delta][center_y-j*delta]=1
    return (img+draw)!=0

def circle(img, nx, ny, parameters):
    r, theta, n = parameters
    draw = np.zeros((nx,ny), dtype=np.int)
    center_x = nx//2
    center_y = ny//2
    for i in range(n):
        shift = r*i
        if((center_x+shift)>=nx or (center_y+shift)>=ny):
            continue
        else:
            rotator = 0
            while(rotator < 2*np.pi):
                new_x = int(round(center_x + shift*np.cos(rotator)))
                new_y = int(round(center_y + shift*np.sin(rotator)))
                #round returns a xx.0 :(
                #print(new_x, new_y)
                draw[new_x][new_y] = 1
                rotator = rotator + theta*np.pi/180
    return (img+draw)!=0

def ellipse(img, nx, ny, parameters):
    return img

savepoint.py

#!/usr/bin/env python3
#coding=utf8
import numpy as np

# 目标分辨率,使用前需改成PZT对应行程,或者注释掉这两行,在import的部分指定
_TARGET_HEIGT = 125*1000
_TARGET_WIDTH = 125*1000

def covert_pmatrix_to_csv(matrix):
    # matrix为一个二维数组,仅有0与非0区分,非0表示打点
    height, width = np.shape(matrix)
    point_list = []
    for i in range(height):
        for j in range(width):
            if(matrix[i][j]==0):
                pass
            else: point_list.append((i,j))
    return point_list

def write_points_to_file(filename, point_list, resolution):
    # filename为一个字符串,表示存储的文件名
    # point_list是一个list类,每个元素是一个tuple,表示坐标
    # resolution是一个tuple,表示point_list范围(绘图的分辨率)
    if(filename[-3:].lower() != "csv"):
        filename=filename+".csv"
    else:
        filename=filename[:-3]+filename[-3:].lower()
        # :P随手转成小写后缀名……
    resx = resolution[0]
    resy = resolution[1]
    if(resolution[0]&1 == 1):
        resx = resolution[0]-1
    if(resolution[1]&1 == 1):
        resy = resolution[0]-1
    with open(filename, 'w') as f:
        for i in point_list:
            real_position = (i[0]/resx*_TARGET_WIDTH - _TARGET_WIDTH/2, i[1]/resy*_TARGET_HEIGT - _TARGET_WIDTH/2)
            f.write('%f, %f\n'%real_position)
    return
Last modification:April 5th, 2019 at 03:20 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment