PyQt5 test: application based on QTableWidget

PyQt5 test: application based on QTableWidget

Foreword:

The content of this article is based on the QtableWidget control, combined with the four-quadrant thinking of time management, to make a simple task priority calculator. You need to have a certain understanding of the Python language and the PyQt5 library. For a quick introduction to PyQt5, you can read the "PyQt5 Beginner Test Record" (← click) series of articles.

Nowadays, it is an era of explosion of all categories. Every day we need to face countless new things, or all kinds of knowledge to be learned, or various tasks that have been planned. What is particularly troublesome is that, What should I do first? There are a variety of time management or work planning apps on the market, which provide a way to clarify their thinking for people who suffer from selection difficulties and procrastination.

In my daily study work, the author also feels distressed about what should be done first in the batch of affairs to be handled. After understanding the thinking of the four quadrants of time management, I only had ideas. Below, the author will introduce a method for scheduling tasks.
Insert picture description here
( In short, I just took something and tried the function of QTableWidget ) The four quadrants of time management, as shown in the figure above. With the two labels of important and urgent, the affairs are divided into four categories, which can make users clearly realize that urgent and important things need to be done first. And when there are many transaction items, it is helpful to control the overall situation and plan the execution sequence of each transaction.

According to this concept, the author established a small model in EXCEL, according to different urgency and importance, set the reference coefficient interval, and add a time coefficient. According to the user's judgment on the task, fill in 3 coefficients to calculate the priority value. The priority value algorithm used by the author here is: urgent X0.6 + important X0.4 + time X0.1 . That is, more urgent matters have greater weight, and time is used as an adjustment value for auxiliary distinction.
Insert picture description here

After calculating the priority value and sorting, you can know the priority order of the tasks. ( Well, I finally put the article writing to the top priority! )
Insert picture description here

Ok, let's use pyqt5 to make this thing! ( Obviously the operation in EXCEL is faster )

To use magic to deal with magic, it is necessary to use a table to implement a table, this time using the QTableWidget control. First, drag and drop in Qt Designer to make the interface. The upper row of buttons is the basic function, and the lower frame is the core control.
Insert picture description here
Insert picture description here

QTableWidget inherits from QTableView. The difference is that the son is not independent enough and only knows the standard data model taught by his father; while the father is knowledgeable and can use strange data. So I choose to educate the immature son here ( that is, QTableView is in trouble ).

First modification __init__method, to add colsand rowsthe number of columns of the table representing a variable number of rows, in a subsequent CRUD operations will be used in. Then set the column width of each column to adapt to the size of the QTableWidget. Because the content of the task item is an indeterminate character, the other columns are all numerical values, that is, the width can basically be unchanged, so you can manually adjust the column width by setting only the first column.

def __init__(self):
    super(ReLearnForm, self).__init__()
    self.setupUi(self)
    self.cols = self.tableWidget.columnCount()
    self.rows = 0 # 任务数
    self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # 自适应列宽
    self.tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.Interactive) # 仅首列可手动调整

Insert picture description here

Here implement the functionality of each button:
. 1, the Read Me
click specification window opens a custom, where ReadForm()a Dialog class.

def read(self):
    self.d = ReadForm()
    self.d.show()
    self.d.setWindowTitle("参数说明")

2 + (increase task)
by rowsrecording the number of tasks currently in the line.

def add_row(self):
    print('添加一行任务记录')
    self.rows += 1
    self.tableWidget.setRowCount(self.rows)

3.- (Delete task)
Before deleting a row, you need to get the currently selected row;

In the __init__method of adding the row_flagvariable is used to index rows (first row 0) of the selected records (when not selected) the initial value of -1. By itemSelectionChangedbinding the cell selection signal and the groove custom function;

self.row_flag = -1 # 当前被选中的行索引
self.result = []
self.tableWidget.itemSelectionChanged.connect(self.chioce) # 单元格选择改变

Custom grooves function choice()to achieve row_flagthe modification;

def chioce(self): # 修改被选中的行索引
    self.row_flag = self.tableWidget.currentRow()
    print(f'选中第{self.row_flag + 1}行')

Write a method to delete rows, modify rowsthem at the same time after deletion , and reset row_flag.

def del_row(self):
    print('删除一行任务记录')
    if self.row_flag == -1:
        QMessageBox.about(self,'提醒','未选择要删除的行!')
    else:
        self.tableWidget.removeRow(self.row_flag) # 删除指定行
        self.rows -= 1
        self.row_flag = -1

4. X (Clear Task)
Set the number of rows in the control to 0 to achieve clearing.

def clean_rows(self):
    print('清空任务记录')
    reply = QMessageBox.question(self, '提示', '请确认是否要清空!', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
    if reply == QMessageBox.Yes:
        self.rows = 0
        self.tableWidget.setRowCount(self.rows)

5. RUN (calculation)
Before explaining the undo operation, first explain the function realized by the RUN button;

In the __init__method of adding the resultvariable for temporarily storing the calculation results;

self.result = []

The method to realize the calculation of priority: ① traverse by row, obtain the input values ​​of the task name, urgency, importance, and time factor in the 4 columns, and calculate the priority p according to the rules described above (rounded to retain 2 decimal places), ② Add the p value to the cell and make it selectable and non-editable. Put the cell in the fifth column of the same row (index 4), which is the priority column. ③ Finally, save the result of each row into the list. The descending priority, and then through resulta variable saved.

def prior_value(self):
    print('计算优先度')
    # print(f"共{self.row_nums}行{self.cols}列数据")
    list_para = []
    try:
        for r in range(self.rows):
            my_item = self.tableWidget.item(r, 0).text() # 任务名称
            urgent = int(self.tableWidget.item(r, 1).text()) # 紧急程度
            important = int(self.tableWidget.item(r, 2).text()) # 重要程度
            t = int(self.tableWidget.item(r, 3).text()) # 时间系数
            p = round(urgent*0.6 + important*0.4 + t*0.1,2) # 优先度
            item_p = QTableWidgetItem(str(p)) # 将优先度值添加为单元格
            item_p.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) # 设置为可选择、不可编辑
            self.tableWidget.setItem(r, 4, item_p)
            list_para.append([my_item, urgent, important, t, p])
        self.result = sorted(list_para, key=lambda x: x[4], reverse=True) # 根据优先度将行元素列表降序
        self.sort_move(self.result)
    except:
        pass

Insert picture description here
The results are calculated at this time, but not yet adjusted to a cell, so that the result of the ordered list of resultincoming sort_move()further processing: from resultacquired value of each column in the rewriting cell, wherein nowthe current row index sorted. QTableWidget does not have the function of uniformly adjusting the center, and it needs to traverse all the cells again to set the center.

def sort_move(self, list_para_sorted): # 根据排序结果重写单元格
    print('执行了sort')
    for now in range(len(list_para_sorted)):
        item_it = QTableWidgetItem(str(list_para_sorted[now][0]))
        item_u = QTableWidgetItem(str(list_para_sorted[now][1]))
        item_im = QTableWidgetItem(str(list_para_sorted[now][2]))
        item_t = QTableWidgetItem(str(list_para_sorted[now][3]))
        item_p = QTableWidgetItem(str(list_para_sorted[now][4]))
        item_p.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)  # 设置为可选择、不可编辑
        print('得到了items')
        self.tableWidget.setItem(now, 0, item_it)
        self.tableWidget.setItem(now, 1, item_u)
        self.tableWidget.setItem(now, 2, item_im)
        self.tableWidget.setItem(now, 3, item_t)
        self.tableWidget.setItem(now, 4, item_p)
        print('设置了items')
    for i in range(int(self.rows)):  # 设置所有单元格文本居中
        for j in range(int(self.cols)):
            self.tableWidget.item(i, j).setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)

The final result is as follows, so far the core function has been realized. But in order to make this ( broken things look more impressive ) tool more perfect, continue to implement the functions of undoing deletion and saving the results to EXCEL.
Insert picture description here

6, ← (left arrow - withdraw)
from resultreading the latest record variable, the first line of recovery, re-use sort_move()way to restore the content, which is the sort_move()single written as a method rather than integrated into the prior_valuereasons for the method.

def return_result(self):
    print('撤销操作')
    print(self.result)
    if self.result:
        self.rows = len(self.result) # 恢复任务数
        self.tableWidget.setRowCount(self.rows) # 恢复行
        self.sort_move(self.result) # 恢复内容

Note: Delete line no content not respond, it will take the current resultvariables content can be restored.

Insert picture description here

7. ↓ (down arrow-save)
( really a tasteless function ) Now it is pandas time! If resultafter not empty, it is written row by row DataFrame save to EXCEL file, and then call os.startfile('.xlsx')to open the file.

def save(self):
    print('保存结果')
    if self.result:
        # [my_item, urgent, important, t, p]
        df = pd.DataFrame(columns=['任务项', '紧急程度', '重要程度', '时间系数', '优先度'])
        for i in range(len(self.result)):
            df.loc[i] = self.result[i]
        df.to_excel('优先度结果表.xlsx', index = False)
        os.startfile('优先度结果表.xlsx')
    else:
        QMessageBox.about(self,'提醒','未产生计算结果!')

Finally, packaged into an executable program, the icon is a thinking pigeon drawn by the author ( cuckoo, even if the task is scheduled, I will not do it on time ). For packaging procedures, please refer to " PyQt5 Beginner Test Record (3): Pyinstaller Packaging Summary ".
Insert picture description here

After completing this gadget, I believe that everyone has a certain understanding of the characteristics of the QTableWidget control, let's apply it to your own gadgets!

thanks for reading! (The source code has been uploaded to gitub: https://github.com/SeonPan/ReLearn )

Guess you like

Origin blog.csdn.net/zohan134/article/details/107238759