linux桌面小程序开发(pyqt+新增csv增删改查功能)附加章节

2023-11-05

温馨提示:

  1. 默认运行的是GPU,若发现无法执行,请在参数中替换为CUP
  2. 在上一版中需要用到sql,但在这一版中我全部改为了csv进行一个文件的匹配,所以不再需要装mysql了,还有创建字段啥的了

我更新了该小程序的功能,增加了csv文件的增删改查功能
功能图片

在这里插入图片描述

博客与B站:

B站视频:https://www.bilibili.com/video/BV1K94y1o72a/
gitee:https://gitee.com/wx_b915676bb6/yolo-pyqt.git
github:https://github.com/liuchengzhiz/yolo_pyqt_food.git
特点:

  1. 同时输出与检测结果与相应相关信息
  2. 支持视频暂停与继续检测
  3. 能够匹配相关信息表
  4. 能够将数据录入在数据库中
  5. 能够对匹配价格和中文的csv文件进行增删改查操作。

目的:

  1. 熟悉PYQT的使用
  2. 了解PyQt5基础控件与布局方法
  3. 了解信号与槽
  4. 熟悉视频在PyQt中的处理方法
  5. 了解数据库在python中的使用方法
  6. 了解了csv文件的增删改查操作

二、快速开始

  • 首先需要大家能够成功运行开源项目yolov5模型
  • 然后在yolov5模型的基础上,pip安装pyqt5这个库
  • 然后即可运行(应该吧)

附上最新的主要代码
在这里插入图片描述

detect_logical

# 
# @Author: Cjuicy 
# @Date: 2022-03-21 16:00:23 
# @Last Modified by:   Cjuicys 
# @Last Modified time: 2022-03-21 16:00:23 
# 


from asyncio.windows_events import NULL
from asyncore import write
from cProfile import label
from pickle import TRUE
import sys
from unittest import result
import cv2
import time
import argparse
import random
import torch
import numpy as np
import pandas as pd
import torch.backends.cudnn as cudnn


from utils.torch_utils import select_device
from models.experimental import attempt_load
from utils.general import check_img_size, non_max_suppression, scale_coords
from utils.datasets import letterbox
from utils.plots import plot_one_box2
from utils.torch_utils import select_device, load_classifier, time_synchronized

'''导入qt库'''
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import csv


'''导入自己的文件'''
from ui.food_ui import Ui_MainWindow
from utils import food_info_utils #,food_sql


class Ui_Logic_Window(QtWidgets.QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)                            #父类的构造函数
        self.cap = cv2.VideoCapture()                       #视频流
        self.timer_video = QtCore.QTimer()                  #定义定时器,用于控制显示视频的帧率
        
        '''csv表格操作'''
        self.price_info,self.names_info = food_info_utils.get_price_info()      # 获取表格价钱信息
        
        '''GUI部分'''
        self.ui = Ui_MainWindow()
        # self.setWindowTitle("慧结算")                       #设置窗口标题名
        
        self.layout_main = self.ui.set_ui()                      #初始化页面布局
        self.layout_main.setWindowIcon(QIcon("./ui/icon/hjs.png"))        #设置icon 不知道为啥在food_ui这个图标就上不去
        
        arr,row = food_info_utils.get_food_info()                   #获取tab2表格数据
        self.ui.refresh_row(arr,row)                            #更新tab2表格数据
        
        # layout_main.show()

        # self.setLayout(layout_main)                         #到这步才会显示所有控件
        self.slot_init()                                    #初始化槽函数
        self.ui.button_settle_accounts.setDisabled(True)    #将结账按钮触发禁用


        '''先定义一些变量'''
        self.num_stop = 1                                   # 暂停与播放辅助信号,note:通过奇偶来控制暂停与播放
        self.output_folder = 'output/'
        self.vid_writer = None
        self.order_info = ''                                #用于存储订单的信息
        self.arr = np.array(arr)                                       #用于存放最新的food_info.csv表的信息

        '''初始化模型'''
        self.openfile_name_model = "./yolov5s.pt"
        self.model_init()

        self.button_camera_open()                           # 打开摄像头检测
        # self.button_video_open()


    
 
    '''槽函数,用于一些触发事件'''
    def slot_init(self):
        
        self.ui.button_confirm.clicked.connect(self.button_video_stop)    
        self.ui.button_settle_accounts.clicked.connect(self.insert_order)
        self.timer_video.timeout.connect(self.show_video_frame) 
        self.ui.button_picture.clicked.connect(self.button_image_open)
        self.ui.add_confirm_button_tab2.clicked.connect(self.button_add_confirm_tab2)
        self.ui.delete_confirm_button_tab2.clicked.connect(self.button_delete_confirm_tab2)
        self.ui.alter_confirm_button_tab2.clicked.connect(self.button_alter_confirm_tab2)
        self.ui.select_confirm_button_tab2.clicked.connect(self.button_select_confirm_tab2)

    

    '''加载相关参数,并初始化模型'''
    def model_init(self):
        parser = argparse.ArgumentParser()
        parser.add_argument('--weights', nargs='+', type=str, default='yolov5s.pt', help='model.pt path(s)')
        parser.add_argument('--source', type=str, default='data/images', help='source')  # file/folder, 0 for webcam
        parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
        parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold')
        parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')
        parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
        parser.add_argument('--view-img', action='store_true', help='display results')
        parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
        parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
        parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
        parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
        parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
        parser.add_argument('--augment', action='store_true', help='augmented inference')
        parser.add_argument('--update', action='store_true', help='update all models')
        parser.add_argument('--project', default='runs/detect', help='save results to project/name')
        parser.add_argument('--name', default='exp', help='save results to project/name')
        parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
        self.opt = parser.parse_args()
        # print(self.opt)
        source, weights, view_img, save_txt, imgsz = self.opt.source, self.opt.weights, self.opt.view_img, self.opt.save_txt, self.opt.img_size

        if self.openfile_name_model:
            weights = self.openfile_name_model
            print("Using button choose model")

        # self.device = select_device(self.opt.device)
        self.device = torch.device('cuda:0')
        self.half = self.device.type != 'cpu'  # half precision only supported on CUDA

        cudnn.benchmark = True

        # Load model
        self.model = attempt_load(weights, map_location=self.device)  # load FP32 model
        stride = int(self.model.stride.max())  # model stride
        self.imgsz = check_img_size(imgsz, s=stride)  # check img_size
        if self.half:
            self.model.half()  # to FP16
        #  Second-stage classifier
        classify = False
        if classify:
            modelc = load_classifier(name='resnet101', n=2)  # initialize
            modelc.load_state_dict(torch.load('weights/resnet101.pt', map_location=self.device)['model']).to(self.device).eval()

        # Get names and colors
        self.names = self.model.module.names if hasattr(self.model, 'module') else self.model.names
        self.colors = [[random.randint(0, 255) for _ in range(3)] for _ in self.names]
        # print("model initial done")
        
        # 设置提示框
        # QtWidgets.QMessageBox.information(self, u"Notice", u"模型加载完成", buttons=QtWidgets.QMessageBox.Ok,
                                    #   defaultButton=QtWidgets.QMessageBox.Ok)




    # 目标检测
    def detect(self, name_list, img):
        '''
        :param name_list: 文件名列表
        :param img: 待检测图片
        :return: info_show:检测输出的文字信息
        '''
        showimg = img
        with torch.no_grad():
            img = letterbox(img, new_shape=self.opt.img_size)[0]
            # Convert
            img = img[:, :, ::-1].transpose(2, 0, 1)  # BGR to RGB, to 3x416x416
            img = np.ascontiguousarray(img)
            img = torch.from_numpy(img).to(self.device)
            img = img.half() if self.half else img.float()  # uint8 to fp16/32
            img /= 255.0  # 0 - 255 to 0.0 - 1.0
            if img.ndimension() == 3:
                img = img.unsqueeze(0)
            # Inference
            pred = self.model(img, augment=self.opt.augment)[0]
            # Apply NMS
            pred = non_max_suppression(pred, self.opt.conf_thres, self.opt.iou_thres, classes=self.opt.classes,
                                       agnostic=self.opt.agnostic_nms)
            info_show = ""

            # --定义标签变量名--
            label_names = ""

            # Process detections
            for i, det in enumerate(pred):
                if det is not None and len(det):
                    # Rescale boxes from img_size to im0 size
                    det[:, :4] = scale_coords(img.shape[2:], det[:, :4], showimg.shape).round()
                    for *xyxy, conf, cls in reversed(det):
                        
                        # if self.names[int(cls)] in self.names_info:                         #将英文替换为中文
                        #     chinese_name = str(self.names_info[self.names[int(cls)]])         #
                            
                        # label = '%s %.2f' % (self.names[int(cls)], conf)                  #原始代码
                        label = '%s %.2f' % (self.names[int(cls)], conf)                    #这是英文
                        # ch_text = '%s %.2f' % (chinese_name, conf)                          #这是中文label 传入plot_one_box2就好 


                        name_list.append(self.names[int(cls)])
                        single_info = plot_one_box2(xyxy, showimg, label=label, color=self.colors[int(cls)], line_thickness=2)
                        # print(single_info)
                        info_show = info_show + single_info + "\n"

                        #获取检测到的所有标签
                        label_names = label_names+","+self.names[int(cls)]
                
            label_names = label_names.split(",")                                # 转化为数组(字符串头有一个',')
            label_names = [i for i in label_names if(len(str(i))!=0)]           # 去掉数组内的空值

        return  info_show , label_names

    '''设置保存的视频名字和路径'''
    def set_video_name_and_path(self):
        now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
        # if vid_cap:  # video
        fps = self.cap.get(cv2.CAP_PROP_FPS)
        w = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        h = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        save_path = self.output_folder + 'video_output/' + now + '.mp4'
        return fps, w, h, save_path


    '''打开摄像头检测'''
    def button_camera_open(self):
        print("Open camera to detect")
        camera_num = 0
        self.cap = cv2.VideoCapture(camera_num)
        bool_open =self.cap.open(camera_num)
        if not bool_open:
            QtWidgets.QMessageBox.warning(self, u"Warning", u"打开摄像头失败", buttons=QtWidgets.QMessageBox.Ok,
                                          defaultButton=QtWidgets.QMessageBox.Ok)
        else:
            fps, w, h, save_path = self.set_video_name_and_path()
            # fps = 5 # 控制摄像头检测下的fps,Note:保存的视频,播放速度有点快,我只是粗暴的调整了FPS
            self.vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
            self.timer_video.start(30)

    '''定义视频帧操作'''
    def show_video_frame(self):
        name_list = []
        flag, img = self.cap.read()
        if img is not None:
            info_show , label_names = self.detect(name_list, img)   # 检测结果写入到原始img上
            self.vid_writer.write(img)                              # 检测结果写入视频
            # print(info_show)

            self.set_labels(label_names)                            # 处理lable并显示在GUI上
            
            

            show = cv2.resize(img, (640, 480))                      # 直接将原始img上的检测结果进行显示
            self.result = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
            showImage = QtGui.QImage(self.result.data, self.result.shape[1], self.result.shape[0],
                                     QtGui.QImage.Format_RGB888)
            # self.ui.label.setPixmap(QtGui.QPixmap.fromImage(showImage))
            self.ui.label_show_camera_tab.setPixmap(QtGui.QPixmap.fromImage(showImage))  #往显示视频的Label里 显示QImage
            # self.ui.label.setScaledContents(True)  # 设置图像自适应界面大小

        else:
            self.timer_video.stop()         # 读写结束,释放资源
            self.cap.release()              # 释放video_capture资源
            self.vid_writer.release()       # 释放video_writer资源
            

            self.ui.button_settle_accounts.setDisabled(True)    # 视频帧显示期间,禁用结账按键功能


    ''' 暂停与继续检测 '''
    def button_video_stop(self):
        self.timer_video.blockSignals(False)
        # 暂停检测
        # 若QTimer已经触发,且激活
        if self.timer_video.isActive() == True and self.num_stop%2 == 1:
            self.ui.button_confirm.setText(u'重新确认')           #当前状态为暂停状态
            self.num_stop = self.num_stop + 1                   # 调整标记信号为偶数

            self.timer_video.blockSignals(True)
            
            self.ui.button_settle_accounts.setDisabled(False)   # 启动结账按钮
        # 继续检测
        else :
            self.num_stop = self.num_stop + 1
            self.ui.button_confirm.setText(u'确认')
            self.ui.button_settle_accounts.setDisabled(True)
        
        


     # 打开图片并检测
    def button_image_open(self):
        self.button_video_stop()                                #将摄像头暂停
        print('button_image_open')
        name_list = []
        try:
            img_name, _ = QtWidgets.QFileDialog.getOpenFileName(self, "打开图片", "data/images", "*.jpg;;*.png;;All Files(*)")
        except OSError as reason:
            print('文件打开出错啦!核对路径是否正确'+ str(reason))
        else:
            # 判断图片是否为空
            if not img_name:
                QtWidgets.QMessageBox.warning(self, u"Warning", u"打开图片失败", buttons=QtWidgets.QMessageBox.Ok,
                                              defaultButton=QtWidgets.QMessageBox.Ok)
                self.button_video_stop()    
            else:
                # self.num_stop = self.num_stop + 1                       #摄像头暂停修正,否则两次图像识别,第二次无法读取图片,这也会导致另一个按钮得点两次(是个大问题)
                img = cv2.imread(img_name)
                print("img_name:", img_name)
                info_show , label_names = self.detect(name_list, img)
                
                # 获取当前系统时间,作为img文件名
                now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
                file_extension = img_name.split('.')[-1]
                new_filename = now + '.' + file_extension # 获得文件后缀名
                file_path = self.output_folder + 'img_output/' + new_filename
                cv2.imwrite(file_path, img)
                
                # 检测信息显示在界面
                self.set_labels(label_names)                            # 处理lable并显示在GUI上
                # self.ui.textBrowser.setText(info_show)

                # 检测结果显示在界面
                self.result = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
                self.result = cv2.resize(self.result, (640, 480), interpolation=cv2.INTER_AREA)
                self.ShowImage = QtGui.QImage(self.result.data, self.result.shape[1], self.result.shape[0], QtGui.QImage.Format_RGB32)
                self.ui.label_show_camera_tab.setPixmap(QtGui.QPixmap.fromImage(self.ShowImage))
                self.ui.label_show_camera_tab.setScaledContents(True)
                
                # self.ui.label.setScaledContents(True) # 设置图像自适应界面大小

    '''处理获取到的lable函数'''
    def set_labels(self ,labels ):
        self.ui.list_show.clearContents()                                               #对表格先进行一个清空
        labels = pd.value_counts(labels)                                                #对标签数组进行重复个数统计

        total_price = 0
        order_sql = []    
        
        if len(labels.index.values) != 0:
            labels_sum = len(labels.index.values)                                       #获取标签总数
            for i in range(labels_sum):
                label_num = str(labels.values[i])                                       #获取对应标签的个数

                if labels.index.values[i] in self.names_info:                           #将英文替换为中文
                    label_name = str(self.names_info[labels.index.values[i]])
                    self.ui.list_show.setItem(i,0,QTableWidgetItem(label_name))         #添加对应标签名字
                else:
                    self.ui.list_show.setItem(i,0,QTableWidgetItem(labels.index.values[i])) #添加没有匹配到中文的名字
               
                
                self.ui.list_show.setItem(i,1,QTableWidgetItem(label_num))              #添加对应标签个数
                #记录数据库要插入的字符 
                order_sql.append(str(labels.index.values[i]))
                order_sql.append(str(label_num))     

                # 判断字典内是否有该key,有添加对应价钱数据,没有则选择默认值(99元)
                if labels.index.values[i] in self.price_info :
                    label_price = str(self.price_info[labels.index.values[i]])
                    self.ui.list_show.setItem(i,2,QTableWidgetItem("¥"+label_price))
                    # 计算总价
                    total_price = total_price + (float(label_price) * int(label_num))
                else :
                    self.ui.list_show.setItem(i,2,QTableWidgetItem("99"))
                    # 计算总价
                    total_price = total_price + (float(99) * int(label_num))



                #设置数据库内容
                if i+1>=labels_sum:                         #判断是不是遍历到了标签最后
                   while(i<5):                              #循环,添加剩余的例如数据库的内容
                       order_sql.append('null')
                       order_sql.append('null')
                       i = i+1


        account = "总价:¥ "+ str(total_price)
        self.ui.label_account.setText(account)

        #设置数据库
        order_sql.insert(0,str(total_price))                #插入总价钱
        order_sql.insert(0,"null")                          #插入id变量
        order_sql.append("CURRENT_TIMESTAMP")               #插入当前时间
        
        # print(order_sql)
        self.order_info = order_sql

    '''插入数据'''
    def insert_order(self):
        price = self.order_info[1]              #获取价钱
        if price == '0':
            QtWidgets.QMessageBox.information(self, u"Notice", u"抱歉,没有识别到食物", buttons=QtWidgets.QMessageBox.Ok,defaultButton=QtWidgets.QMessageBox.Ok)
            self.button_video_stop()
        else:
            # 设置提示框
            click = QtWidgets.QMessageBox.information(self, u"Notice", u"您确定结账吗", 
            QtWidgets.QMessageBox.Yes|QtWidgets.QMessageBox.No)
            if(click == QMessageBox.Yes):
                with open("./food_csv.csv", "a+",newline='') as csvfile:
                    writer = csv.writer(csvfile)
                    writer.writerow(self.order_info)
                    csvfile.close()
                    QtWidgets.QMessageBox.information(self, u"Notice", u"结账成功", buttons=QtWidgets.QMessageBox.Ok,defaultButton=QtWidgets.QMessageBox.Ok)
                    self.button_video_stop()
            else:
                self.button_video_stop()
        
        # food_sql.insert_order_info(self.order_info)
        #  显示数据
        # food_sql.select_order_info()

     # 打开视频并检测
    def button_video_open(self):
        # video_name, _ = QtWidgets.QFileDialog.getOpenFileName(self, "打开视频", "data/", "*.mp4;;*.avi;;All Files(*)")
        flag = self.cap.open('C:/Users/24265/Desktop/3.mp4')
        if not flag:
            QtWidgets.QMessageBox.warning(self, u"Warning", u"打开视频失败", buttons=QtWidgets.QMessageBox.Ok,defaultButton=QtWidgets.QMessageBox.Ok)
        else:
            #-------------------------写入视频----------------------------------#
            fps, w, h, save_path = self.set_video_name_and_path()
            self.vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))

            self.timer_video.start(30) # 以30ms为间隔,启动或重启定时器
            # 进行视频识别时,关闭其他按键点击功能
            # self.ui.pushButton_video.setDisabled(True)
            # self.ui.pushButton_img.setDisabled(True)
            # self.ui.pushButton_camer.setDisabled(True)

    #按钮查询功能
    def button_select_confirm_tab2(self):
        str1 = self.ui.select_LineEdit_tab2.text()
        if len(str1) ==0:                                   #判断字符是否为空
            self.ui.select_lable.setText("请输入数据")
            return 0

        if str1.find("_") == -1:                            #检测出是中文
            for i in range(self.arr.shape[0]):
                if  str1 == self.arr[i][2]:
                    self.ui.select_lable.setText( "行号:"+str(i+1)+" 拼音:"+self.arr[i][0]+" 价格:¥"+self.arr[i][1]+" 中文:"+self.arr[i][2])
                    break
                else:
                    self.ui.select_lable.setText("抱歉没有找到该菜品")
        else:                                               #为拼音
            for i in range(self.arr.shape[0]):
                if  str1 == self.arr[i][0]:
                    self.ui.select_lable.setText( "行号:"+str(i+1)+" 拼音:"+self.arr[i][0]+" 价格:¥"+self.arr[i][1]+" 中文:"+self.arr[i][2])
                    break
                else:
                    self.ui.select_lable.setText("抱歉没有找到该菜品")
        return 0 
    
    #检查是否为中文字符
    def check_contain_chinese(self,check_str):
        for ch in check_str:
            if u'\u4e00' <= ch <= u'\u9fff':
                return True     
            else:
                return False

    #查询按钮重构——查询的表是food_info表
    def select_list_tab2(self,str2):
        flag = -1
        str1 = str(str2)
        str1 = str1.replace("_",'')                                #将短横线去除
        str1 = str1.replace(" ",'')
        print(str1)

        #flag 为空:0
        if len(str1) == 0:                                   #判断字符是否为空
            flag = 0                                        #为空返回零
            return flag

        #flag 拼音重复:1 为拼音:2
        if str1.encode('UTF-8').isalpha():                                 #如果为拼音
            for i in range(self.arr.shape[0]):
                if  str2 == self.arr[i][0]:                 #str2是没有去掉_的拼音
                    flag = 1                                #拼音重复
                    return flag
            
            flag = 2                                #为拼音
            return flag
        #flag 为数字:3
        if str1.isdigit():
            flag = 3                                        #为数字
            return flag

        #为重复中文:3 为中文:5
        if self.check_contain_chinese(str1):
            for i in range(self.arr.shape[0]):
                if  str1 == self.arr[i][2]:
                    flag = 4                                #重复中文返回4
                    return flag
            flag = 5                                #为中文
            return flag

        return flag   

    def button_add_confirm_tab2(self):
        str1 = self.ui.add_LineEdit_tab2_1.text()                                       #获取输入框内的数据
        str2 = self.ui.add_LineEdit_tab2_2.text()
        str3 = self.ui.add_LineEdit_tab2_3.text()

        select_result_1 = self.select_list_tab2(str1)                                   #返回结果 检查拼音
        select_result_2 = self.select_list_tab2(str2)
        select_result_3 = self.select_list_tab2(str3)                                   #检查 中文
        print(select_result_1,select_result_2,select_result_3)


        if len(str1) == 0 or len(str2)== 0 or len(str3)==0:                            #判断字符是否为空
            self.ui.add_hint_lable.setText("请将数据填写在输入框中")
            return 0
        elif select_result_1 ==  1:
            self.ui.add_hint_lable.setText("已存在该拼音")
            return 0
        elif select_result_1 != 2:
            self.ui.add_hint_lable.setText("请输入拼音")
            return 0
        elif select_result_2 != 3:
            self.ui.add_hint_lable.setText("在第二个输入框内请填入数字")
            return 0 
        elif select_result_3 == 4:
            self.ui.add_hint_lable.setText("已存在中文")
            return 0
        elif select_result_3 !=5:
            self.ui.add_hint_lable.setText("请输入中文")
            return 0
        else:
            arr = np.array([str1,str2,str3])                                        #数组追加内容到最后
            self.arr = np.r_[self.arr,[arr]]        
            food_info_utils.add_arr_food_info_csv(arr)                              #将添加的内容添加到csv表格内
            self.ui.refresh_row(self.arr,self.arr.shape[0])
            self.ui.add_hint_lable.setText("添加成功")
            self.price_info,self.names_info = food_info_utils.get_price_info()      # 更新信息,让检测时,信息即使改变     
        return 0 

    def button_delete_confirm_tab2(self):
        str1 = self.ui.delete_LineEdit_tab2_1.text()
        if str1.isdigit() == False:
            self.ui.delete_hint_lable.setText("请输数字")
            return 0

        num = int(str1)
        if num > 0 and num<=len(self.arr):
            self.arr = np.delete(self.arr,num-1,0)
            print(self.arr)
            food_info_utils.delete_arr_food_info_csv(num-1) #这些数据编号都是从0开始,所以需要减1
            arr,row = food_info_utils.get_food_info()                   #获取tab2表格数据
            self.ui.refresh_row(arr,row)                                #表格刷新
            self.arr = np.array(arr)                                    #更新存放在内存的数组
            self.ui.delete_hint_lable.setText("删除成功")
            self.price_info,self.names_info = food_info_utils.get_price_info()      # 更新信息,让检测时,信息即使改变
        else:
            self.ui.delete_hint_lable.setText("请输入准确行号")


        return 0 

    def button_alter_confirm_tab2(self):
        str1 = self.ui.alter_LineEdit_tab2_1.text()
        str2 = self.ui.alter_LineEdit_tab2_2.text()
        str3 = self.ui.alter_LineEdit_tab2_3.text()
        str4 = self.ui.alter_LineEdit_tab2_4.text()

        if len(str1) != 0:                                                          #不为空
            if str1.isdigit():                                                      #如果为数字
                num = int(str1)
                if num>0 and num<=len(self.arr):
                    pass
                else:
                    self.ui.alter_hint_lable.setText("请输入准确行号")
                    return 0 
            else:
                self.ui.alter_hint_lable.setText("请输入数字")
                return 0
        else:
            self.ui.alter_hint_lable.setText("请输入行号") 
            return 0 



        str2 = str2.replace("_",'')                                                 #将_去掉
        str2 = str2.replace(" ",'')
        if len(str2) != 0:                                                          #不为空
            if str2.encode('UTF-8').isalpha():                                        #如果为拼音
                pass
            else:
                self.ui.alter_hint_lable.setText("请输入拼音")
                return 0 

        if len(str3) != 0:                                                          #不为空
            if str3.isdigit():                                                      #如果为数字
                pass
            else:
                self.ui.alter_hint_lable.setText("请输入数字")
                return 0 
        
        if len(str4) != 0:                                                          #不为空
            if self.check_contain_chinese(str4):                                    #如果为中文
                pass
            else:
                self.ui.alter_hint_lable.setText("请输入中文")
                return 0
        
        arr = [str2,str3,str4]
        if len(str1) != 0:
            food_info_utils.alter_arr_food_info_csv(num-1,arr)
        arr,row = food_info_utils.get_food_info()                   #获取tab2表格数据
        self.ui.refresh_row(arr,row)                                #表格刷新
        self.arr = np.array(arr)                                    #更新存放在内存的数组
        self.ui.alter_hint_lable.setText("修改成功")
        self.price_info,self.names_info = food_info_utils.get_price_info()      # 更新信息,让检测时,信息即使改变
        

        
        


        
        
if __name__ == '__main__':
    app =  QtWidgets.QApplication(sys.argv)
    current_ui =Ui_Logic_Window()                   #实例化Ui_MainWindow
    current_ui.layout_main.show()                               #调用ui的show()以显示。同样show()是源于父类QtWidgets.QWidget的
    sys.exit(app.exec_())
    input("please input any key to exit!")


food_info_utils.py
用于操作csv文件
在这里插入图片描述

# 
# @Author: Cjuicy 
# @Date: 2022-03-21 20:25:16 
# @Last Modified by:   Cjuicys 
# @Last Modified time: 2022-03-21 20:25:16 
# 
'''
存放价钱的读函数
'''
import csv
from matplotlib.pyplot import axis
import numpy as np
import pandas as pd 

from pip import main


# 读取csv文件获得价钱信息  
#注意csv不能有多余空行,最下面只能有一个空行(否则会报错)
def get_price_info():
    price_info = {}
    names_info = {}
    with open('foodInfo.csv', 'r',encoding="utf-8") as csvfile: # 此目录即是当前项目根目录
        spamreader = csv.reader(csvfile)
        # 逐行遍历csv文件,按照字典存储用户名与密码
        for row in spamreader:
            price_info[row[0]] = row[1]
            names_info[row[0]] = row[2]
    return price_info,names_info

    

#读取csv文件获得价钱信息
def get_food_info():
    arr_all=[]
    with open('foodInfo.csv', 'r',encoding="utf-8") as csvfile: # 此目录即是当前项目根目录
        spamreader = csv.reader(csvfile)
        # 逐行遍历csv文件,按照字典存储用户名与密码
        for row in spamreader:
            arr_all.append(row)
    arr_all = np.array(arr_all)
    return arr_all, arr_all.shape[0]

'''对foodInfo.csv增加操作'''
def add_arr_food_info_csv(new_arr):
    with open('foodInfo.csv', 'a+',newline="" ,encoding="utf-8") as csvfile: # 此目录即是当前项目根目录
        wf = csv.writer(csvfile)
        wf.writerow(new_arr)
    return 0

'''对foodInfo.csv删除操作'''
def delete_arr_food_info_csv(num):
    df = pd.read_csv("foodInfo.csv",header=None,encoding="utf-8")
    num = int(num)
    df = df.drop(num)
    df.to_csv("foodInfo.csv",index=0,header=None,encoding="utf-8")
    return 0

'''对foodInfo.csv修改操作'''
def alter_arr_food_info_csv(num,arr):
    arr = np.array(arr)


    data = pd.read_csv("foodInfo.csv",header=None,encoding="utf-8")
    if len(arr[0])!=0:
        data.iat[num,0] = arr[0]                    #替换csv指定位置替换        应为没有标题,所以都是用编号为索引
    
    if len(arr[1])!=0:
        data.iat[num,1] = arr[1]
    
    if len(arr[2])!=0:
        data.iat[num,2] = arr[2]
    data.to_csv("foodInfo.csv",index=0,header=None,encoding="utf-8")
    return 0

# if __name__ == '__main__':
#     get_price_info()

food_ui
设计UI界面的函数
在这里插入图片描述

# @Author: Cjuicy 
# @Date: 2022-03-21 16:07:16 
# @Last Modified by:   Cjuicys 
# # @Last Modified time: 2022-03-21 16:07:16  */

from select import select
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from matplotlib import widgets
import numpy as np



class Ui_MainWindow(object):
    

    '''程序界面布局'''
    def set_ui(self):
        
        

        '''设置主界面'''
        self.__layout_main =QTabWidget()
        
        '''创建三个小控件窗口'''
        self.__layout_main_tab1 =QtWidgets.QWidget()            #tab1总布局界面
        self.__layout_main_tab2 = QtWidgets.QWidget()           #tab2的总布局界面

        '''将三个选项卡添加到顶层窗口中'''
        self.__layout_main.addTab(self.__layout_main_tab1,"识别")
        self.__layout_main.addTab(self.__layout_main_tab2,"管理")

        '''每个选项卡自定义内容'''
        self.tab1UI()
        self.tab2UI()

        # self.__layout_main.setWindowIcon(QIcon("./icon/hjs.png"))
        self.__layout_main.setWindowTitle("慧结算") 




        # self.__layout_main = QtWidgets.QGridLayout()                #总布局
        # self.__layout_fun_button1 = QtWidgets.QHBoxLayout()         #按键布局1
        # self.__layout_fun_button2 = QtWidgets.QHBoxLayout()         #按键布局2
        # self.__layout_data_show = QtWidgets.QVBoxLayout()           #数据(视频)显示布局
        # self.__layout_list_show  = QtWidgets.QVBoxLayout()          #表格布局


        # self.button_confirm = QtWidgets.QPushButton('确认')         #建立用于打开摄像头的按键
        # self.button_settle_accounts = QtWidgets.QPushButton('结账') #建立结账的按钮
        # self.button_picture = QtWidgets.QPushButton("图片识别")     #建立图片识别的按钮
        # self.list_show =  QtWidgets.QTableWidget(6,3)               #建立表格
        # self.label_account = QtWidgets.QLabel("总价:")              #建立label


        # '''set butten size '''
        # self.button_confirm.setMinimumHeight(50)                    #设置按键大小
        # self.button_settle_accounts.setMinimumHeight(50)
        # self.button_picture.setMinimumHeight(50)              
        # self.label_account.setMinimumHeight(50)                     #设置label大小
        

        # # self.button_close.move(10,100)                      #移动按键  这句话去掉好像也没关系
        # '''设置标签的格式'''
        # font = QtGui.QFont()
        # font.setPixelSize(18)
        # self.label_account.setFont(font)

        # '''设置表格'''
        # self.list_show.setHorizontalHeaderLabels(["名称","数量","单价"])
        # self.list_show.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)# adaptive size
        # self.list_show.setEditTriggers(QAbstractItemView.EditTrigger(False))    #将表格的内容设为不可编辑
        # '''信息显示'''
        # self.label_show_camera = QtWidgets.QLabel()                                 #定义显示视频的Label
        # self.label_show_camera.setFixedSize(641,481)                                #给显示视频的Label设置大小为641x481
        # '''把按键加入到按键布局中'''
        # self.__layout_fun_button1.addWidget(self.button_confirm)                    #把重新确认的按键放到按键布局中
        # self.__layout_fun_button1.addWidget(self.button_picture)                    #吧图片识别放到按键布局中
        # self.__layout_fun_button2.addWidget(self.button_settle_accounts)            #把结账的按键放到按键布局中
        
        # '''把表格加入到表格布局中'''
        # self.__layout_list_show.addWidget(self.list_show)                           #将表格添加到表格布局中
        # self.__layout_list_show.addWidget(self.label_account)                       #将总价label添加到表格布局中


        # '''设置按钮布局之间的间隔'''
        # self.__layout_fun_button1.setSpacing(20)                                    #设置控件距离

        

        # '''把某些控件加入到总布局中'''
        # self.__layout_main.addLayout(self.__layout_list_show,0,0)        #将表格布局添加到总布局中
        # self.__layout_main.addLayout(self.__layout_fun_button1,1,1)      #把按键布局加入到总布局中
        # self.__layout_main.addLayout(self.__layout_fun_button2,1,0)      #把按键布局加入到总布局中
        # self.__layout_main.addWidget(self.label_show_camera,0,1)        #把用于显示视频的Label加入到总布局中


        return self.__layout_main
 

    def tab1UI(self):
        '''与外界接触的按键需要用到self'''

        
                
        # self.__layout_main = QtWidgets.QGridLayout()                #总布局
        layout_main_tab = QtWidgets.QGridLayout()           #tab1总布局界面
        layout_fun_button1_tab = QtWidgets.QHBoxLayout()         #按键布局1
        layout_fun_button2_tab = QtWidgets.QHBoxLayout()         #按键布局2
        layout_data_show_tab = QtWidgets.QVBoxLayout()           #数据(视频)显示布局
        layout_list_show_tab  = QtWidgets.QVBoxLayout()          #表格布局

        self.button_confirm = QtWidgets.QPushButton('确认')         #建立用于打开摄像头的按键
        self.button_settle_accounts = QtWidgets.QPushButton('结账') #建立结账的按钮
        self.button_picture = QtWidgets.QPushButton("图片识别")     #建立图片识别的按钮
        self.list_show =  QtWidgets.QTableWidget(6,3)               #建立表格
        self.label_account = QtWidgets.QLabel("总价:")              #建立label
        
        '''set butten size '''
        self.button_confirm.setMinimumHeight(50)                    #设置按键大小
        self.button_settle_accounts.setMinimumHeight(50)
        self.button_picture.setMinimumHeight(50)              
        self.label_account.setMinimumHeight(50)                     #设置label大小
        
        '''设置标签的格式'''
        font = QtGui.QFont()
        font.setPixelSize(18)
        self.label_account.setFont(font)
        
        '''设置表格'''
        self.list_show.setHorizontalHeaderLabels(["名称","数量","单价"])
        self.list_show.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)# adaptive size
        self.list_show.setEditTriggers(QAbstractItemView.EditTrigger(False))    #将表格的内容设为不可编
        '''信息显示'''
        self.label_show_camera_tab = QtWidgets.QLabel()                                 #定义显示视频的Label
        self.label_show_camera_tab.setFixedSize(641,481)                                #给显示视频的Label设置大小为641x481
        
        '''把按键加入到按键布局中'''
        layout_fun_button1_tab.addWidget(self.button_confirm)                    #把重新确认的按键放到按键布局中
        layout_fun_button1_tab.addWidget(self.button_picture)                    #吧图片识别放到按键布局中
        layout_fun_button2_tab.addWidget(self.button_settle_accounts)            #把结账的按键放到按键布局中
        
        '''把表格加入到表格布局中'''
        layout_list_show_tab.addWidget(self.list_show)                           #将表格添加到表格布局中
        layout_list_show_tab.addWidget(self.label_account)                       #将总价label添加到表格布局中
        
        '''设置按钮布局之间的间隔'''
        layout_fun_button1_tab.setSpacing(20)                                    #设置控件距离
        
        '''把某些控件加入到总布局中'''
        layout_main_tab.addLayout(layout_list_show_tab,0,0)        #将表格布局添加到总布局中
        layout_main_tab.addLayout(layout_fun_button1_tab,1,1)      #把按键布局加入到总布局中
        layout_main_tab.addLayout(layout_fun_button2_tab,1,0)      #把按键布局加入到总布局中
        layout_main_tab.addWidget(self.label_show_camera_tab,0,1)        #把用于显示视频的Label加入到总布局中


        self.__layout_main_tab1.setLayout(layout_main_tab)

    def tab2UI(self):
        layout_main_tab = QtWidgets.QGridLayout()           #tab2总布局界面

        # layout_main_tab.setColumnStretch(2,1)             #设置格栅布局行和列的占比
        layout_main_tab.setRowStretch(1,0)
        
        layout_list_show_tab  = QtWidgets.QVBoxLayout()            #表格布局
        layout_select_show_tab  = QtWidgets.QVBoxLayout()            #查询板块布局
        layout_tab_show_tab   = QtWidgets.QVBoxLayout()
        
        layout_tab_show  = QtWidgets.QTabWidget()            #其他三个功能tab组件

        '''创建3个小功能布局'''
        self.layout_add_tab2 = QtWidgets.QWidget()            #增加
        self.layout_delete_tab2 = QtWidgets.QWidget()         #删除
        self.layout_alter_tab2 = QtWidgets.QWidget()          #修改


        '''将三个选项卡添加到顶层窗口中'''
        layout_tab_show.addTab(self.layout_add_tab2,'增加')
        layout_tab_show.addTab(self.layout_alter_tab2,'修改')
        layout_tab_show.addTab(self.layout_delete_tab2,'删除')

        '''添加到tab布局中'''
        layout_tab_show_tab.addWidget(layout_tab_show)
        

        '''每个小功能tab布局'''
        self.tab2UI_add()
        
        self.tab2UI_alter()
        self.tab2UI_delete()



        select__title = QtWidgets.QLabel("查询")
        select_hint_label = QtWidgets.QLabel("请输入食物的拼音或中文名")     #查询label提示控件
        self.select_LineEdit_tab2 = QtWidgets.QLineEdit()             #查询输入框控件
        self.select_confirm_button_tab2 =  QtWidgets.QPushButton('确定')     #查询按钮控件
        self.select_lable = QtWidgets.QLabel("数据为:")                #显示查询出来的数据
        

        self.list_show_tab2  = QtWidgets.QTableWidget()            #表格控件

        '''表格具体设计'''
        self.list_show_tab2.setRowCount(0)        #初始行数0行
        self.list_show_tab2.setColumnCount(3)
        self.list_show_tab2.setHorizontalHeaderLabels(['拼音','单价','中文'])
        self.list_show_tab2.setHidden(False)        #显示行号
        
        '''控件添加到分布局'''
        
        layout_list_show_tab.addWidget(self.list_show_tab2)
        

        layout_select_show_tab.addWidget(select__title)
        layout_select_show_tab.addWidget(select_hint_label)
        layout_select_show_tab.addWidget(self.select_LineEdit_tab2)
        layout_select_show_tab.addWidget(self.select_confirm_button_tab2)
        layout_select_show_tab.addWidget(self.select_lable)


        '''分布局添加到tab2总布局'''
        layout_main_tab.addLayout(layout_list_show_tab,0,0,2,1)     #最后两个参数,占两行,1列
        layout_main_tab.addLayout(layout_select_show_tab,0,1)
        layout_main_tab.addLayout(layout_tab_show_tab,1,1)
        
        self.__layout_main_tab2.setLayout(layout_main_tab)



    '''tab2表格的更新操作'''
    def refresh_row(self,arr_all,row_num):
        self.list_show_tab2.clearContents()
        self.list_show_tab2.setRowCount(row_num)
        for i in range(row_num):
            self.list_show_tab2.setItem(i,0,QTableWidgetItem(arr_all[i][0]))
            self.list_show_tab2.setItem(i,1,QTableWidgetItem(arr_all[i][1]))
            self.list_show_tab2.setItem(i,2,QTableWidgetItem(arr_all[i][2]))
            

    def tab2UI_add(self):
        '''定义tab2的add布局'''
        layout_add_main_tab = QtWidgets.QVBoxLayout()


        add_hint_label_1 = QtWidgets.QLabel("*请输入食物的拼音")     #查询label提示控件
        self.add_LineEdit_tab2_1 = QtWidgets.QLineEdit()             #拼音输入框控件
        add_hint_label_2 = QtWidgets.QLabel("*请输入食物的价格")
        self.add_LineEdit_tab2_2 = QtWidgets.QLineEdit()             #价格输入框控件
        add_hint_label_3 = QtWidgets.QLabel("*请输入食物的中文")
        self.add_LineEdit_tab2_3 = QtWidgets.QLineEdit()             #中文输入框控件
        self.add_confirm_button_tab2 =  QtWidgets.QPushButton('添加')     #添加按钮控件
        self.add_hint_lable = QtWidgets.QLabel("")                #显示提示信息

        '''将控件添加到小布局中'''
        layout_add_main_tab.addWidget(add_hint_label_1)
        layout_add_main_tab.addWidget(self.add_LineEdit_tab2_1)
        layout_add_main_tab.addWidget(add_hint_label_2)
        layout_add_main_tab.addWidget(self.add_LineEdit_tab2_2)
        layout_add_main_tab.addWidget(add_hint_label_3)
        layout_add_main_tab.addWidget(self.add_LineEdit_tab2_3)
        layout_add_main_tab.addWidget(self.add_confirm_button_tab2)
        layout_add_main_tab.addWidget(self.add_hint_lable)


        '''将布局添加到总布局'''
        self.layout_add_tab2.setLayout(layout_add_main_tab)

        return 0 



    def tab2UI_alter(self):
        '''定义tab2的alter布局'''
        layout_alter_main_tab = QtWidgets.QVBoxLayout()

        alter_row_hint_label_1 = QtWidgets.QLabel("*请输入行号")          #修改label提示控件
        self.alter_LineEdit_tab2_1 = QtWidgets.QLineEdit()             #行号输入框控件
        alter_hint_label_1 = QtWidgets.QLabel("食物的拼音(可不填)")     #查询label提示控件
        self.alter_LineEdit_tab2_2 = QtWidgets.QLineEdit()             #拼音输入框控件
        alter_hint_label_2 = QtWidgets.QLabel("食物的价格(可不填)")
        self.alter_LineEdit_tab2_3 = QtWidgets.QLineEdit()             #价格输入框控件
        alter_hint_label_3 = QtWidgets.QLabel("食物的中文(可不填)")
        self.alter_LineEdit_tab2_4 = QtWidgets.QLineEdit()             #中文输入框控件
        self.alter_confirm_button_tab2 =  QtWidgets.QPushButton('修改')     #添加按钮控件
        self.alter_hint_lable = QtWidgets.QLabel("")                #显示提示信息

        '''将控件添加到小布局中'''
        layout_alter_main_tab.addWidget(alter_row_hint_label_1)
        layout_alter_main_tab.addWidget(self.alter_LineEdit_tab2_1)
        layout_alter_main_tab.addWidget(alter_hint_label_1)
        layout_alter_main_tab.addWidget(self.alter_LineEdit_tab2_2)
        layout_alter_main_tab.addWidget(alter_hint_label_2)
        layout_alter_main_tab.addWidget(self.alter_LineEdit_tab2_3)
        layout_alter_main_tab.addWidget(alter_hint_label_3)
        layout_alter_main_tab.addWidget(self.alter_LineEdit_tab2_4)
        layout_alter_main_tab.addWidget(self.alter_confirm_button_tab2)
        layout_alter_main_tab.addWidget(self.alter_hint_lable)


        '''将布局添加到总布局'''
        self.layout_alter_tab2.setLayout(layout_alter_main_tab)
        return 0 





    def tab2UI_delete(self):
        '''定义tab2的delete布局'''
        layout_delete_main_tab = QtWidgets.QVBoxLayout()


        add_hint_label_1 = QtWidgets.QLabel("请输入行号")     #查询label提示控件
        self.delete_LineEdit_tab2_1 = QtWidgets.QLineEdit()             #拼音或中文输入框控件
        self.delete_confirm_button_tab2 =  QtWidgets.QPushButton('删除')     #添加按钮控件
        self.delete_hint_lable = QtWidgets.QLabel("")                #显示提示信息

        '''将控件添加到小布局中'''
        layout_delete_main_tab.addWidget(add_hint_label_1)
        layout_delete_main_tab.addWidget(self.delete_LineEdit_tab2_1)
        layout_delete_main_tab.addWidget(self.delete_confirm_button_tab2)
        layout_delete_main_tab.addWidget(self.delete_hint_lable)


        '''将布局添加到总布局'''
        self.layout_delete_tab2.setLayout(layout_delete_main_tab)

        return 0 


最后附上两张表的截图,一个用于信息的匹配
另一个用于存放结账存储的数据
在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux桌面小程序开发(pyqt+新增csv增删改查功能)附加章节 的相关文章

随机推荐

  • 话题:程序员酒后吐真言,竟然这样说

    据说 美国最大的论坛 Reddit 最近有一个热帖 一个程序员说自己喝醉了 做了10年软件工程师 心里有好多话想说 我可能会后悔今天说了这些话 他洋洋洒洒写了一大堆 获得9700多个赞 其中有一条竟然是说 作为一名工程师 最被低估的技能是记
  • 数据结构与算法之图的广度优先遍历

    数据结构与算法之图的广度优先遍历 前要 图的广度优先遍历 树 VS 图 树的层序遍历 图 广度优先遍历 代码实现图广度优先遍历 方法说明 代码示例 算法存在的问题 算法复杂度分析 邻接矩阵存储的图 邻接表存储的图 广度优先生成树 广度优先生
  • 2023年第三届控制理论与应用国际会议

    会议简介 Brief Introduction 2023年第三届控制理论与应用国际会议 ICoCTA 2023 会议时间 2023年10月20 22日 召开地点 中国 厦门 大会官网 www icocta org 控制理论作为一门科学技术
  • 两电源之间接0.1UF的电容起什么作用?

    应该起的是滤波的作用 1 高频滤波电容的配置 A 小于10个输出的小规模集成电路 工作频率 50MHz时 至少配接一个0 1 f的滤波电容 工作频率 50MHz时 每个电源引脚配接一个0 1 f的滤波电容 B 对于中大规模集成电路 每个电源
  • Oracle根据某个字段去重并查询出第一条数据

    表结构 要求 查询出无重复GLRDM的GLRDM GLRMC数据 SQL SELECT a GLRDM a GLRMC FROM SELECT b row number over partition BY GLRDM ORDER BY GL
  • idea只读模式(注释变为*)

    强迫症患者 习惯了idea的 注解 突然不小心点了idea的 注解 想要变回来的解决方式 idea注释突然变成不可编辑模式 此时可以调整Reader Mode 把Enable Reader mode取消即可 以上就是我对idea变为只读模式
  • Orange‘s:一个操作系统的实现学习笔记1

    安装虚拟机 bochs NASM 前言 一 安装虚拟机VMware和操作系统 安装Ubuntu 安装VMTools 1 提示直接安装 2 点击选项安装 安装后记 二 安装bochs和NASM 1 安装bochs 2 安装NASM 安装后记
  • Perl 函数参考

    Perl wait 函数 wait该函数等待子进程终止 返回已故进程的进程ID 进程的退出状态包含在 中 句法 以下是此函数的简单语法 wait 返回值 如果没有子进程 则此函数返回 1 否则将显示已故进程的进程ID Perl waitpi
  • JVM的运行时内存区域划分详细讲解

    文章目录 一 运行时数据区域 1 程序计数器 Program Counter Register 2 Java 虚拟机栈 Java Virtual Machine Stacks 3 本地方法栈 Native Method Stack 4 Ja
  • 【VirtualBox系列】VirtualBox设置虚拟机网络绝对详细

    前言知识 在学习配置网络之前 我们需要先了解下关于virtualBox的三种网络模式 搞懂虚拟机VirtualBox网络配置 需求分析 现在如何实现一种效果 我想达到主机可以访问虚拟机 并且虚拟机能够访问外网 还有如果我更换了路由器 之前配
  • Excel基础操作

    目录 第一节 新建Excel工作簿 第二节 认识Excel操作界面 第三节 上下文选项卡和自定义功能区 第四节 文件选项卡的设置 第五节 输入和编辑数据 第六节 数据的显示 第七节 数据输入技巧 第八节 填充与序列 第九节 填充选项 第十节
  • LVGL学习 stm32f407-board-lvgl v8.3移植

    LVGL学习 stm32f407 board lvglv8 3移植 移植过程有问题 请参考正点原子的教程或者视频 硬件平台 STM32F407ZGT6核心板 3 2寸屏幕 LVGL LVGL Light and Versatile Grap
  • CloudCompare 二次开发(3)——计算点云质心

    目录 一 概述 二 代码集成 三 结果展示 一 概述 不依赖任何第三方点云相关库 使用ClopudCompare计算点云质心 本文由CSDN点云侠原创 原文链接 爬虫网站自重 二 代码集成 1 mainwindow h文件public中添加
  • Python数据分析是什么?为什么要对比Excel学习

    Python本身是一门编程语言 应用于Web开发 爬虫 机器学习等多个领域 但是除了这些 今天小千要告诉你Python大热的一个学习方向 那就是Python数据分析 我常常会听到这样的问题 金融分析中 为什么我要学习像Python这样的编程
  • H5跳转微信小程序,通过获取URL Scheme,实现短信跳转小程序,微信跳转小程序,邮件跳转小程序,外部链接跳转小程序

    H5链接跳转小程序有2种方式 第一种 通过微信官方提供的标签wx open launch weapp 打开小程序 第二种 通过获取URL Scheme实现链接跳转小程序 一 wx open launch weapp 官方文档https de
  • java 读取word_java poi word读取

    用 poi 读取word文件 老是报错 org apache poi poifs filesystem NotOLE2FileException Invalid header signature read 0xC9D33C3A6D6F724
  • 期货开户的具体程序是什么?

    一 开户 1 对客户的条件要求 客户应至少具备以下条件 1 具有完全民事行为能力 2 有与进行期货交易相适应的自有资金或者其他财产 能够承担期货交易风险 3 有固定的住所 4 符合国家 行业的有关规定 二 保证金 中小投资者可以等待股指期货
  • tinyMCE编辑器去除换行增加的P标签

    tinyMCE编辑器去除换行增加的P标签 tinyMCE里使用回车后会加P标签 如何变成原本的br标签呢 搜索出force p newlines false参数可以关闭自动添加P标签 但实际测试没什么变化 查询了一下源码发现带 p 的就fo
  • 视差动画 - 雅虎新闻摘要加载

    基础知识 继 Android实现旋转动画的两种方式 我们了解了 Android实现旋转的两种基本方法之后 我们来写一个综合案例 效果展示 代码实现 实现思路 从效果中我们可以看到 可以将其分为三个动画 1 旋转动画 Android实现旋转动
  • linux桌面小程序开发(pyqt+新增csv增删改查功能)附加章节

    温馨提示 默认运行的是GPU 若发现无法执行 请在参数中替换为CUP 在上一版中需要用到sql 但在这一版中我全部改为了csv进行一个文件的匹配 所以不再需要装mysql了 还有创建字段啥的了 我更新了该小程序的功能 增加了csv文件的增删