『pyqt5 从0基础开始项目实战』05. 按钮点击事件之添加新数据 (保姆级图文)

news2024/12/23 22:20:25

目录

    • 导包和框架代码
    • 给按钮绑定一个点击事件
    • 获取输入框的数据
    • 多线程与界面更新(新线程与UI更新的数据交互)
      • 代码结构
    • 完整代码
      • main文件
      • Threads.py
    • 总结


欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中
欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中

导包和框架代码

import os
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton, QLineEdit, QTableWidget, QTableWidgetItem, QLabel
from PyQt5.QtWidgets import QMessageBox, QMenu

#拿到在另外一台计算机上执行程序代码所存储的文件路径。
BASE_DIR = os.path.dirname(os.path.realpath(sys.argv[0]))

STATUS_MAPPING = {
    0: "初始化中",
    1: "待执行",
    2: "正在执行",
    3: "完成并提醒",
    10: "异常并停止",
    11: "初始化失败",
}


class MainWindow(QWidget):
    def __init__(self):
        # 用super 继承父类的初始化
        super().__init__()

        # 设置窗口的窗体标题
        self.setWindowTitle('发现你走远了的xx系统')

        # 设置窗体的尺寸
        self.resize(1228, 450)

        # 设置窗体位置
        # 获取整个窗口部分的宽高和左上角坐标信息,返回值是一个QRect类型,(x,y width,height)
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()  # 得到屏幕中间的位置信息
        qr.moveCenter(cp)  # 让我们的窗体移动到屏幕中间

        # 创建窗口总布局
        layout = QVBoxLayout()

        # 讲调用方法生成的顶部菜单布局添加到总布局
        layout.addLayout(self.init_header())
        layout.addLayout(self.init_form())
        layout.addLayout(self.init_table())
        layout.addLayout(self.init_footer())

        # 给窗体设置元素的排列方式
        self.setLayout(layout)

    def init_header(self):
        # 1.顶部菜单布局
        header_layout = QHBoxLayout()  # 创建顶部菜单布局
        # 1.1 放入按钮
        btn_start = QPushButton("开始")  # 新建一个开始按钮
        header_layout.addWidget(btn_start)  # 将开始按钮添加到顶部菜单布局
        btn_stop = QPushButton("停止")  # 新建一个开始按钮
        header_layout.addWidget(btn_stop)  # 将开始按钮添加到顶部菜单布局
        # 1.2 加入弹簧
        header_layout.addStretch()

        return header_layout

    def init_form(self):
        # 2.添加内容布局
        form_layout = QHBoxLayout()  # 创建添加内容布局

        # 2.1 输入框
        txt_asin = QLineEdit()  # 新建一个输入框对象
        txt_asin.setText("B07YN82X3B=100")  # 设置默认的form数据
        txt_asin.setPlaceholderText("请输入商品ID和价格,例如:B0818JJQQ8=88")  # 设置灰色的提示信息
        form_layout.addWidget(txt_asin)  # 将输入框加入到布局中

        # 2.2 添加按钮
        btn_add = QPushButton("添加")  # 新建一个添加按钮
        form_layout.addWidget(btn_add)  # 将添加按钮添加到form布局

        return form_layout

    def init_table(self):
        # 3.表格数据展示布局
        table_layout = QHBoxLayout()
        # 3.1 创建表格
        table_widget = QTableWidget(0, 8)  # 新建一个0行8列的表格
        # # 修改表格索引名
        # item=QTableWidgetItem()
        # item.setText("标题0")
        # table_widget.setHorizontalHeaderItem(0,item)
        # table_widget.setColumnWidth(0,150)#设置水平单元格0号位置的宽度 150
        #
        # item2=QTableWidgetItem()
        # item2.setText("网址1")
        # table_widget.setHorizontalHeaderItem(1,item2)
        # table_widget.setColumnWidth(1,400)#设置水平单元格1号位置的宽度 400
        #
        # item3=QTableWidgetItem()
        # item3.setText("行索引0")
        # table_widget.setVerticalHeaderItem(0,item3)
        table_header = [
            {"field": "asin", "text": "ASIN", 'width': 120},
            {"field": "title", "text": "标题", 'width': 150},
            {"field": "url", "text": "URL", 'width': 400},
            {"field": "price", "text": "底价", 'width': 100},
            {"field": "success", "text": "成功次数", 'width': 100},
            {"field": "error", "text": "503次数", 'width': 100},
            {"field": "status", "text": "状态", 'width': 100},
            {"field": "frequency", "text": "频率(N秒/次)", 'width': 100},
        ]
        for idx, info in enumerate(table_header):
            item = QTableWidgetItem()
            item.setText(info['text'])
            table_widget.setHorizontalHeaderItem(idx, item)
            table_widget.setColumnWidth(idx, info['width'])

        # 3.2 初始化表格数据
        # 读取数据文件
        import json
        file_path = os.path.join(BASE_DIR, "db", "db.json")
        with open(file_path, mode='r', encoding='utf-8') as f:
            data = f.read()
        data_list = json.loads(data)#读取得到了json数据


        current_row_count = table_widget.rowCount()  # 当前表格有多少行
        for row_list in data_list:#每有一行json数据,我们就需要遍历一轮增加一行数据
            table_widget.insertRow(current_row_count)#增加一行
            # print(row_list)  # ['B08166SLDF', 'AMD er', 'https://www.amazon.', 300.0, 0, 166, 1, 5]
            # 把row_list写入这一行
            for i, ele in enumerate(row_list):#enumerate中 i表示索引id,ele表示数据值
                # 一个多目运算 如果i==6(此时是状态的数据) 如果STATUS_MAPPING中能够找到ele的索引,那么我们把ele设置成STATUS_MAPPING中的内容
                ele = STATUS_MAPPING[ele] if i == 6 else ele

                cell = QTableWidgetItem(str(ele))#注意我们的数据格式转为str,比如说状态的数据可能本身是int类型
                if i in [0, 4, 5, 6]:
                    # 不可修改
                    cell.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)#指定索引单元格不能选中和修改
                table_widget.setItem(current_row_count, i, cell)#写入数据到指定单元格

            current_row_count += 1 #行数+1,这样下次遍历行时会在新的行下面新增一行
            # 如果不新增行其实也可以用  current_row_count=table_widget.rowCount()替代


        table_layout.addWidget(table_widget)  # 把表格添加到表格布局中
        return table_layout

    def init_footer(self):
        # 4.底部菜单
        footer_layout = QHBoxLayout()

        label_status = QLabel("未检测", self)
        footer_layout.addWidget(label_status)

        footer_layout.addStretch()  # 添加弹簧,更加美观

        btn_reset = QPushButton("重新初始化")
        footer_layout.addWidget(btn_reset)

        btn_recheck = QPushButton("重新检测")
        footer_layout.addWidget(btn_recheck)

        btn_reset_count = QPushButton("次数清零")
        footer_layout.addWidget(btn_reset_count)

        btn_delete = QPushButton("删除检测项")
        footer_layout.addWidget(btn_delete)

        btn_alert = QPushButton("SMTP报警配置")
        footer_layout.addWidget(btn_alert)

        btn_proxy = QPushButton("代理IP")
        footer_layout.addWidget(btn_proxy)

        return footer_layout


if __name__ == '__main__':
    app = QApplication(sys.argv)  # 实例化一个Application应用,所有的窗口均在其下运行

    window = MainWindow()  # 实例化窗口对象
    window.show()  # 窗口展示

    sys.exit(app.exec_())
    # app.exec_()运行主循环,并在退出时返回状态代码。
    # sys.exit(n)退出您的应用程序并返回n到父进程(通常是您的shell)


给按钮绑定一个点击事件

    def init_form(self):
    	·····
        # 2.2 添加按钮
        btn_add = QPushButton("添加")  # 新建一个添加按钮
        btn_add.clicked.connect(self.event_add_click)#新增一个点击事件
        form_layout.addWidget(btn_add)  # 将添加按钮添加到form布局
    # 定义的点击事件方法
    def event_add_click(self):
    	·····

获取输入框的数据

利用self定义全局变量来获取form布局子方法中定义的控件对象。

  • 先初始化定义一个self.txt_asin=None
class MainWindow(QWidget):
    def __init__(self):
        # 用super 继承父类的初始化
        super().__init__()
        
        self.txt_asin=None
  • 在form子布局中给框赋值self.txt_asin=txt_asin
    def init_form(self):
        # 2.添加内容布局
        form_layout = QHBoxLayout()  # 创建添加内容布局

        # 2.1 输入框
        txt_asin = QLineEdit()  # 新建一个输入框对象
        txt_asin.setText("B07YN82X3B=100")  # 设置默认的form数据
        txt_asin.setPlaceholderText("请输入商品ID和价格,例如:B0818JJQQ8=88")  # 设置灰色的提示信息
        self.txt_asin=txt_asin
        form_layout.addWidget(txt_asin)  # 将输入框加入到布局中
        pass
  • 在点击事件中获得输入框中的值
    先修改 self.table_widget=table_widget = QTableWidget(0, 8) # 新建一个0行8列的表格 表示全局初始化了table_widget
    def init_table(self):
        self.table_widget=table_widget = QTableWidget(0, 8)  # 新建一个0行8列的表格
    def event_add_click(self):
        # 1.获取输入框中的内容
        text = self.txt_asin.text()
        text = text.strip()#去掉空格
        if not text:#如果输入的是空格空字符
            QMessageBox.warning(self, "错误", "商品的ASIN输入错误")
            return
        # B07YN82X3B=100
        asin, price = text.split("=")#把数据分为id 和 价格
        price = float(price)#价格转为浮点型
  • 将数据写入表格,操作和上一篇文章的代码一样,注意的是,这里也要全局变量获取得到table对象
  • 这里用了table 的另一种写法
        # 2.加入到表格中(型号、底价)
        new_row_list = [asin, "", "", price, 0, 0, 0, 5]

        # 写入表格,具体操作和之前初始化表格一样
        current_row_count = self.table_widget.rowCount()  # 当前表格有多少行
        self.table_widget.insertRow(current_row_count)
        for i, ele in enumerate(new_row_list):
            ele = STATUS_MAPPING[ele] if i == 6 else ele
            cell = QTableWidgetItem(str(ele))
            if i in [0, 4, 5, 6]:
                # 不可修改
                cell.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            self.table_widget.setItem(current_row_count, i, cell)

我们已经成功添加了新数据
在这里插入图片描述


多线程与界面更新(新线程与UI更新的数据交互)

  • 我们要实现的功能是新建数据后根据商品的ASIN生成url,然后通过爬虫获取url中的商品标题等数据,然后更新在我们的桌面应用中。

  • 因为考虑到大家不一定有相关的爬虫基础和网络原因的限制,而且网站的更新也会影响代码能否长期正常使用,所以我干脆简化了爬虫流程,只是给大家模拟这个过程。

  • 首先关键的一点,我们的数据获取代码不能在主线程中,必须在新建的线程中!(为什么?)

    • 如果在主线程中,那么我们的界面会在数据获取的爬虫代码结束前不能使用(因为还在执行爬虫代码)所以为了我们能够并行界面功能和数据获取功能,必须要有新的线程。

代码结构

py文件同级目录下新建utils 其中新建threads.py文件
在这里插入图片描述
线程与ui更新的大致流程:

  1. 定义一个线程,传入线程需要的参数,比如我们这里的总行数和当前行号
  2. 主文件添加connect回调,编写回调函数(根据得到的数据进行窗体的更新)
  3. 线程中设置信号success = pyqtSignal(int, str, str, str) # 成功后向ui对象发送数据的声明
  4. 线程中通过self.success.emit(self.row_index, self.asin, title, url)提交数据返回

完整代码

main文件

import os
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton, QLineEdit, QTableWidget, QTableWidgetItem, QLabel
from PyQt5.QtWidgets import QMessageBox, QMenu
# from utils.dialog import LogDialog

#拿到在另外一台计算机上执行程序代码所存储的文件路径。
BASE_DIR = os.path.dirname(os.path.realpath(sys.argv[0]))

STATUS_MAPPING = {
    0: "初始化中",
    1: "待执行",
    2: "正在执行",
    3: "完成并提醒",
    10: "异常并停止",
    11: "初始化失败",
}



class MainWindow(QWidget):
    def __init__(self):
        # 用super 继承父类的初始化
        super().__init__()

        self.txt_asin=None

        # 设置窗口的窗体标题
        self.setWindowTitle('发现你走远了的xx系统')

        # 设置窗体的尺寸
        self.resize(1228, 450)

        # 设置窗体位置
        # 获取整个窗口部分的宽高和左上角坐标信息,返回值是一个QRect类型,(x,y width,height)
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()  # 得到屏幕中间的位置信息
        qr.moveCenter(cp)  # 让我们的窗体移动到屏幕中间

        # 创建窗口总布局
        layout = QVBoxLayout()

        # 讲调用方法生成的顶部菜单布局添加到总布局
        layout.addLayout(self.init_header())
        layout.addLayout(self.init_form())
        layout.addLayout(self.init_table())
        layout.addLayout(self.init_footer())

        # 给窗体设置元素的排列方式
        self.setLayout(layout)

    def init_header(self):
        # 1.顶部菜单布局
        header_layout = QHBoxLayout()  # 创建顶部菜单布局
        # 1.1 放入按钮
        btn_start = QPushButton("开始")  # 新建一个开始按钮
        header_layout.addWidget(btn_start)  # 将开始按钮添加到顶部菜单布局
        btn_stop = QPushButton("停止")  # 新建一个开始按钮
        header_layout.addWidget(btn_stop)  # 将开始按钮添加到顶部菜单布局
        # 1.2 加入弹簧
        header_layout.addStretch()

        return header_layout

    def init_form(self):
        # 2.添加内容布局
        form_layout = QHBoxLayout()  # 创建添加内容布局

        # 2.1 输入框
        txt_asin = QLineEdit()  # 新建一个输入框对象
        txt_asin.setText("B07YN82X3B=100")  # 设置默认的form数据
        txt_asin.setPlaceholderText("请输入商品ID和价格,例如:B0818JJQQ8=88")  # 设置灰色的提示信息
        self.txt_asin=txt_asin
        form_layout.addWidget(txt_asin)  # 将输入框加入到布局中

        # 2.2 添加按钮
        btn_add = QPushButton("添加")  # 新建一个添加按钮
        btn_add.clicked.connect(self.event_add_click)#新增一个点击事件
        form_layout.addWidget(btn_add)  # 将添加按钮添加到form布局

        return form_layout

    def init_table(self):
        # 3.表格数据展示布局
        table_layout = QHBoxLayout()
        # 3.1 创建表格
        self.table_widget=table_widget = QTableWidget(0, 8)  # 新建一个0行8列的表格
        # # 修改表格索引名
        # item=QTableWidgetItem()
        # item.setText("标题0")
        # table_widget.setHorizontalHeaderItem(0,item)
        # table_widget.setColumnWidth(0,150)#设置水平单元格0号位置的宽度 150
        #
        # item2=QTableWidgetItem()
        # item2.setText("网址1")
        # table_widget.setHorizontalHeaderItem(1,item2)
        # table_widget.setColumnWidth(1,400)#设置水平单元格1号位置的宽度 400
        #
        # item3=QTableWidgetItem()
        # item3.setText("行索引0")
        # table_widget.setVerticalHeaderItem(0,item3)
        table_header = [
            {"field": "asin", "text": "ASIN", 'width': 120},
            {"field": "title", "text": "标题", 'width': 150},
            {"field": "url", "text": "URL", 'width': 400},
            {"field": "price", "text": "底价", 'width': 100},
            {"field": "success", "text": "成功次数", 'width': 100},
            {"field": "error", "text": "503次数", 'width': 100},
            {"field": "status", "text": "状态", 'width': 100},
            {"field": "frequency", "text": "频率(N秒/次)", 'width': 100},
        ]
        for idx, info in enumerate(table_header):
            item = QTableWidgetItem()
            item.setText(info['text'])
            table_widget.setHorizontalHeaderItem(idx, item)
            table_widget.setColumnWidth(idx, info['width'])

        # 3.2 初始化表格数据
        # 读取数据文件
        import json
        file_path = os.path.join(BASE_DIR, "db", "db.json")
        with open(file_path, mode='r', encoding='utf-8') as f:
            data = f.read()
        data_list = json.loads(data)#读取得到了json数据


        current_row_count = table_widget.rowCount()  # 当前表格有多少行
        for row_list in data_list:#每有一行json数据,我们就需要遍历一轮增加一行数据
            table_widget.insertRow(current_row_count)#增加一行
            # print(row_list)  # ['B08166SLDF', 'AMD er', 'https://www.amazon.', 300.0, 0, 166, 1, 5]
            # 把row_list写入这一行
            for i, ele in enumerate(row_list):#enumerate中 i表示索引id,ele表示数据值
                # 一个多目运算 如果i==6(此时是状态的数据) 如果STATUS_MAPPING中能够找到ele的索引,那么我们把ele设置成STATUS_MAPPING中的内容
                ele = STATUS_MAPPING[ele] if i == 6 else ele

                cell = QTableWidgetItem(str(ele))#注意我们的数据格式转为str,比如说状态的数据可能本身是int类型
                if i in [0, 4, 5, 6]:
                    # 不可修改
                    cell.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)#指定索引单元格不能选中和修改
                table_widget.setItem(current_row_count, i, cell)#写入数据到指定单元格

            current_row_count += 1 #行数+1,这样下次遍历行时会在新的行下面新增一行
            # 如果不新增行其实也可以用  current_row_count=table_widget.rowCount()替代


        table_layout.addWidget(table_widget)  # 把表格添加到表格布局中
        return table_layout

    def init_footer(self):
        # 4.底部菜单
        footer_layout = QHBoxLayout()

        label_status = QLabel("未检测", self)
        footer_layout.addWidget(label_status)

        footer_layout.addStretch()  # 添加弹簧,更加美观

        btn_reset = QPushButton("重新初始化")
        footer_layout.addWidget(btn_reset)

        btn_recheck = QPushButton("重新检测")
        footer_layout.addWidget(btn_recheck)

        btn_reset_count = QPushButton("次数清零")
        footer_layout.addWidget(btn_reset_count)

        btn_delete = QPushButton("删除检测项")
        footer_layout.addWidget(btn_delete)

        btn_alert = QPushButton("SMTP报警配置")
        footer_layout.addWidget(btn_alert)

        btn_proxy = QPushButton("代理IP")
        footer_layout.addWidget(btn_proxy)

        return footer_layout

    def event_add_click(self):
        # 1.获取输入框中的内容
        text = self.txt_asin.text()
        text = text.strip()#去掉空格
        if not text:#如果输入的是空格空字符
            QMessageBox.warning(self, "错误", "商品的ASIN输入错误")
            return
        # B07YN82X3B=100
        asin, price = text.split("=")#把数据分为id 和 价格
        price = float(price)#价格转为浮点型
        print(asin, price)

        # 2.加入到表格中(型号、底价)
        new_row_list = [asin, "", "", price, 0, 0, 0, 5]

        # 写入表格,具体操作和之前初始化表格一样
        current_row_count = self.table_widget.rowCount() # 当前表格有多少行
        self.table_widget.insertRow(current_row_count)
        for i, ele in enumerate(new_row_list):
            ele = STATUS_MAPPING[ele] if i == 6 else ele
            cell = QTableWidgetItem(str(ele))
            if i in [0, 4, 5, 6]:
                # 不可修改
                cell.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            self.table_widget.setItem(current_row_count, i, cell)

        # 3.发送请求自动获取标题
        # 注意:不能再主线程中做数据获取的事,创建一个线程去做数据获取,爬取到数据再更新到窗体应用(信号)。
        from utils.threads import NewTaskThread #导入我们写的线程py文件中的类

        thread = NewTaskThread(current_row_count, asin, self)#初始化线程中类的对象,传入了 表格总共的行数{current_row_count} 和 当前在表格的第几行{asin} 以及自身这个对象 {self}
        thread.success.connect(self.init_task_success_callback)#添加数据成功事件成功的回调,马上开始初始化数据
        thread.error.connect(self.init_task_error_callback)#事件失败的回调,弹框提示错误
        thread.start()#线程开始运行

        pass


    # 添加数据成功事件成功的回调,得到数据后马上开始初始化数据
    def init_task_success_callback(self, row_index, asin, title, url):
        print( row_index, asin, title, url)
        # 更新标题
        cell_title = QTableWidgetItem(title)
        self.table_widget.setItem(row_index, 1, cell_title)

        # 更新URL
        cell_url = QTableWidgetItem(url)
        self.table_widget.setItem(row_index, 2, cell_url)

        # 更新状态
        cell_status = QTableWidgetItem(STATUS_MAPPING[1])
        cell_status.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.table_widget.setItem(row_index, 6, cell_status)

        # 输入框清空
        self.txt_asin.clear()

    # 添加数据失败事件成功的回调,得到数据后马上开始初始化数据
    def init_task_error_callback(self, row_index, asin, title, url):
        print("错误",row_index, asin, title, url)
        # 更新标题
        cell_title = QTableWidgetItem(title)
        self.table_widget.setItem(row_index, 1, cell_title)

        # 更新URL
        cell_url = QTableWidgetItem(url)
        self.table_widget.setItem(row_index, 2, cell_url)

        # 更新状态
        cell_status = QTableWidgetItem(STATUS_MAPPING[11])
        cell_status.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.table_widget.setItem(row_index, 6, cell_status)



if __name__ == '__main__':
    app = QApplication(sys.argv)  # 实例化一个Application应用,所有的窗口均在其下运行

    window = MainWindow()  # 实例化窗口对象
    window.show()  # 窗口展示

    sys.exit(app.exec_())
    # app.exec_()运行主循环,并在退出时返回状态代码。
    # sys.exit(n)退出您的应用程序并返回n到父进程(通常是您的shell)

Threads.py

from PyQt5.QtCore import QThread, pyqtSignal


class NewTaskThread(QThread):
    # 信号,触发信号,更新窗体中的数据
    success = pyqtSignal(int, str, str, str)  # 成功后向ui对象发送数据的声明
    error = pyqtSignal(int, str, str, str)  # 失败后向ui对象发送数据的声明

    def __init__(self, row_index, asin, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.row_index = row_index  # 行数
        self.asin = asin  # 商品id

    def run(self):
        """ 具体线程应该做的事"""
        try:
            title = "good_title_{}".format(self.asin)  # good_title_B07YN82X3B
            url = "https://blog.csdn.net/u011027547/{}".format(self.asin)

            # 获取到title和url,将这个信息填写到 表格上 & 写入文件中。
            self.success.emit(self.row_index, self.asin, title, url)
        except Exception as e:
            print(e)
            title = "监控项 {} 添加失败。".format(self.asin)
            self.error.emit(self.row_index, self.asin, title, str(e))

在这里插入图片描述


总结

大家喜欢的话,给个👍,点个关注!给大家分享更多计算机专业学生的求学之路!

版权声明:

发现你走远了@mzh原创作品,转载必须标注原文链接

Copyright 2023 mzh

Crated:2023-3-1

欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中
欢迎关注 『pyqt5 从0基础开始项目实战』 专栏,持续更新中
『未完待续』


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/424914.html

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

相关文章

上海亚商投顾:沪指创年内新高 大金融、中字头集体走强

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 市场情绪 沪指今日低开高走,午后涨超1%,创出近10个月以来新高,创业板指走势较弱&#xf…

不走弯路,AI真的能提高生产效率

AI应用虽然取得了令人瞩目的成果,但是在实际应用中仍存在不少困境。市面上不乏有AI绘画、AI写作、AI聊天的相关产品,即使Chatgpt可以写代码、写论文,但由于技术的有限性,还需要不断地优化完善才能给出更精准的答复,也少…

契约锁与多家软件行业伙伴达成战略合作,携手助力组织数字化转型

近日,契约锁电子签章与天翼云、神州数码、同望科技、宏灿软件、甄零科技、正量科技等多家软件行业伙伴达成战略合作,充分发挥各自专业与资源优势,从产品、市场、销售、技术等多方面展开深度合作,共同为客户提供全程数字化解决方案…

zabbix创建自定义监控模板

目录 第一章先行配置zabbix 第二章配置自定义 2.1.案列:自定义监控客户端服务器登录的人数需求:限制登录人数不超过 3 个,超过 3 个就发出报警信息 2.2.在 Web 页面创建自定义监控项模板 2.3.zabbix 自动发现与自动注册 总结 自定义监控…

【论文精度(李沐老师)】Generative Adversarial Nets

Abstract 我们提出了一个新的framework,通过一个对抗的过程来估计生成模型,其中会同时训练两个模型:生成模型G来获取整个数据的分布,辨别模型D来分辨数据是来自于训练样本还是生成模型G。生成模型G的任务是尽量的让辨别模型D犯错…

DI依赖注入

DI依赖注入Setter注入setter注入引用类型setter注入简单类型(基本数据类型和字符串)构造器注入构造器注入引用类型自动装配集合注入首先我们明确一些观点1、注入的Bean的数据包括引用类型与简单类型(基本数据类型和字符串)2、通过…

HTML5 地理定位

HTML5 Geolocation(地理定位) HTML5 Geolocation(地理定位)用于定位用户的位置。 Geolocation 通过请求一个位置信息,用户同意后,浏览器会返回一个包含经度和维度的位置信息! 定位用户的位置 …

【C语言数组部分】

数组部分综述引入:数组概念:一、一维数组1.1一维数组的创建:1.2一维数组的初始化:1.2.1初始化概念:1.2.2完全初始化:1.2.3不完全初始化:1.3字符数组的初始化:1.3.1用字符初始化&…

如何解决spring的循环依赖问题?

前言 昨天我们说了什么是spring的循环依赖,以及产生的原因,今天那我们就来说说如何解决spring的循环依赖问题。 上篇文章说到过,只有通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题是被解决的? Spring是怎样解决…

rhce第二次作业

配置ssh免密登陆,能够通过客户端主机通过redhat用户和服务端主机基于公钥验证方式进行远程连接 [root456 ~]# hostname host [root456 ~]# bash \\更改名称[roothost ~]# su redhat …

2023年腾讯云S5云服务器性能网络收发包PPS、连接数、内网带宽能力等性能测评

腾讯云服务器标准型S5实例CPU采用Intel Xeon Cascade Lake或者Intel Xeon Cooper Lake处理器,主频2.5GHz,睿频3.1GHz,标准型S5云服务器基于全新优化虚拟化平台,配有全新的Intel Advanced Vector Extension (AVX-512) 指令集&#…

微服务+springcloud+springcloud alibaba学习笔记【Spring Cloud服务网关】(7/9)

Spring Cloud服务网关 7/91、GateWay概述2、GateWay的特性:3、GateWay与zuul的区别:4、zuul1.x的模型:5、什么是webflux:6、GateWay三大概念:6.1,路由:6.2,断言:6.3,过滤:7、GateWay的工作原理:8、使用GateWay:8.1,建module8.2,修改pom文件8.3,写配置文件8.4,主启动类8.5,针对p…

Springboot 整合 Redis 进行基本操作

SpringBoot整合Redis 首先创建 Springboot 项目。 spring-data-redis针对jedis提供了如下功能:1.连接池自动管理,并提供了一个高度封装的“RedisTemplate”类2.针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口ValueOperat…

计网第六章.应用层各协议概览

以下来自湖科大计算机网络公开课笔记及个人所搜集资料 目录一. C/S方式和P2P对等方式二. 动态主机配置协议DHCP三.域名系统DNS域名解析过程四.文件传输协议FTP基本工作原理:五.电子邮件六.万维网www万维网的文档6.1 HTTP(HyperText Transfer Protocol&am…

左手Python 右手R —— 最大公约数和最小公倍数

左手Python 右手R —— 最大公约数和最小公倍数前言1、 最大公约数1.1 约数1.2 最大公约数1.3 求解方法2、 最小公倍数2.1 倍数2.2 最小公倍数2.3 求解方法3、程序实现3.1 python 代码实现3.2 R语言代码实现小结创作不易,都浏览到这儿了,看官可否将下面的…

【Linux系统创建,修改用户和组和修改目录文件的权限以及实验的心得体会】

实验过程 1.创建一个新用户nick,设置其主目录为home/nick。 (1)添加新用户: sudo useradd -m 用户名 sudo passwd 新用户名 (2)给新用户可以执行的root权限 sudo vi /etc/sudoers #User privilege specification roo…

Spring Security实战(一)——基于内存和数据库模型的认证与授权

目录 简介 一、初识Spring Security(入门案例) (1)新建project (2)选择依赖 (3)编写一个 HelloController (4)启动项目,访问localhost:8080…

手动清除gitlab中prometheus的数据

背景: gitlab服务器上, 磁盘经常爆满。后来通过 du -sh ./* 查出prometheus下的data占了绝大多数磁盘空间。 因此,准备删除prometheus的数据。 思路 由于prometheus的数据占用的空间较大,因此在实际使用时,可以关闭…

【 Spring MVC 核心功能(一) - 使用注解实现 URL 路由映射】

文章目录引言一、RequestMapping 注解介绍1.1 RequestMapping 是 post 还是 get 请求?1.2 RequestMapping 指定一种请求方式二、GetMapping三、PostMapping四、总结引言 前面我们讲到,学习 Spring MVC 需要掌握三个核心功能即连接,获取参数&…

avi文件怎么转成mp4视频,3种方法快速学

avi文件怎么转成mp4视频?前面小编给大家讲了mov格式和webm格式,以及如何将mov和webm格式转换成mp4格式。今天小编给大家说一说另外一种视频格式,就是avi,AVI英文全称为Audio Video Interleaved,即音频视频交错格式&…