PyQt5中的事件与信号处理

news2024/11/29 3:43:29

文章目录

    • 1. 简介
      • 1.1事件(Event)
      • 1.2 信号(Signal)与槽(Slot)
      • 1.3 自定义信号
    • 2. 一个信号与槽的简单示例1
    • 3. 一个信号与槽的简单示例2
    • 4. 事件发送者
    • 5. 创建自定义信号
    • 6. 一个简单计算器

1. 简介

在PyQt5中,事件和信号处理是GUI编程的核心概念。事件是指用户操作或系统消息(如鼠标点击、键盘输入、窗口大小变化等),而信号是指对象之间的通信机制,用于在一个事件发生时通知其他对象执行相应的操作。PyQt5提供了丰富的类和方法来处理事件和信号。

1.1事件(Event)

事件是用户与应用程序交互时发生的动作或状态变化,例如点击鼠标、按键盘等。在PyQt5中,每个窗口小部件(widget)都有一个事件处理器(event handler),它用于处理与该小部件相关的事件。

事件处理器是一个函数,它接收一个事件对象作为参数,并根据事件的类型执行相应的操作。常用的事件处理器包括:

  • mousePressEvent():处理鼠标按下事件。
  • mouseReleaseEvent():处理鼠标释放事件。
  • keyPressEvent():处理键盘按下事件。
  • resizeEvent():处理窗口大小变化事件。

以下是一个简单的示例,演示如何在PyQt5中处理鼠标点击事件:

from PyQt5.QtWidgets import QApplication, QLabel

class MyLabel(QLabel):
    def mousePressEvent(self, event):
        print("鼠标点击了标签!")

app = QApplication([])
label = MyLabel("点击我!")
label.show()
app.exec_()
  • 首先,导入了QApplicationQLabel类,它们分别是QtWidgets模块中用于创建应用程序和标签的类。
  • 接着,定义了一个继承自QLabel的子类MyLabel。在MyLabel类中,重写了mousePressEvent()方法,该方法在鼠标点击事件发生时被调用。当鼠标点击标签时,会在控制台输出消息“鼠标点击了标签!”。
  • 创建了一个QApplication对象,作为整个应用程序的实例。这是每个PyQt5应用程序的必需步骤。
  • 创建了一个MyLabel对象,并传入了一个字符串参数作为标签的文本内容。
  • 调用show()方法显示标签窗口,使其可见。
  • 调用exec_()方法启动应用程序的事件循环,使应用程序保持运行状态,直到用户退出。在此期间,应用程序将等待用户交互事件,例如鼠标点击、键盘输入等。

运行如下图
在这里插入图片描述

鼠标点击窗口里的三个字,就会触发事件,在控制台输出

在这里插入图片描述

1.2 信号(Signal)与槽(Slot)

信号和槽是PyQt5中用于对象之间通信的机制。当一个对象发出信号时,其他对象可以连接到该信号,并在信号触发时执行相应的槽函数。

  • 信号是对象发出的事件,例如按钮被点击、文本框内容变化等。
  • 槽是响应信号的函数,可以是对象的任意方法。

PyQt5中的大多数小部件都有一些内置的信号,例如按钮的clicked信号、文本框的textChanged信号等。可以使用connect()方法将信号连接到槽函数上。

以下是一个示例,演示如何连接按钮的clicked信号到槽函数:

from PyQt5.QtWidgets import QApplication, QPushButton

def on_button_clicked():
    print("按钮被点击了!")

app = QApplication([])
button = QPushButton("点击我!")
button.clicked.connect(on_button_clicked)
button.show()
app.exec_()
  • 这里,我们定义了一个名为on_button_clicked()的函数。这个函数没有参数,当按钮被点击时会被调用,它的作用是在控制台输出消息“按钮被点击了!”。
  • 创建了一个QPushButton对象,并传入了一个字符串参数作为按钮的文本内容。
  • 调用了按钮的clicked信号,并使用connect()方法将其连接到on_button_clicked()函数上。这意味着当按钮被点击时,on_button_clicked()函数会被调用。

运行如下图

在这里插入图片描述

鼠标点击窗口里的三个字,就会触发事件,在控制台输出

在这里插入图片描述

1.3 自定义信号

除了使用内置信号外,还可以自定义信号来实现对象之间的通信。可以使用pyqtSignal()方法创建自定义信号,然后使用emit()方法发出信号。

以下是一个示例,演示如何创建并使用自定义信号:

from PyQt5.QtCore import QObject, pyqtSignal

class MyObject(QObject):
    my_signal = pyqtSignal(str)

    def do_something(self):
        # 发出信号
        self.my_signal.emit("Hello from custom signal!")

def on_custom_signal(value):
    print("接收到自定义信号:", value)

obj = MyObject()
obj.my_signal.connect(on_custom_signal)
obj.do_something()
  • 首先,导入了QObjectpyqtSignal类,它们分别是QtCore模块中用于创建对象和自定义信号的类。
  • 接着,定义了一个名为MyObject的类,它继承自QObject。在MyObject类中,创建了一个名为my_signal的类属性,它是一个pyqtSignal对象,用于定义一个带有一个字符串参数的自定义信号。
  • MyObject类中定义了一个名为do_something()的方法。在这个方法中,调用了self.my_signal.emit()方法发出自定义信号,并传入了字符串参数"Hello from custom signal!"。
  • 接下来,定义了一个名为on_custom_signal()的函数,它有一个参数value,用于接收信号发出的参数。在这个函数中,打印了接收到的自定义信号和传入的参数。
  • 创建了一个MyObject对象,用于发出自定义信号。
  • 调用了对象的my_signal信号,并使用connect()方法将其连接到on_custom_signal()函数上。这样,当MyObject对象发出自定义信号时,on_custom_signal()函数会被调用。
  • 调用了do_something()方法,触发了自定义信号的发出。一旦自定义信号发出,与之连接的槽函数on_custom_signal()就会被调用,打印出"Hello from custom signal!"。

运行上面程序,我们有如下结果

在这里插入图片描述

2. 一个信号与槽的简单示例1

下面是一个简单的示例,展示了如何使用PyQt5创建一个拨动(QDial)和一个LCD数字显示屏(QLCDNumber),当拨动改变时,LCD数字显示屏会实时更新显示拨动的值。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QDial, QLCDNumber

class DialLCDExample(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        # 设置窗口标题和大小
        self.setWindowTitle('拨动与LCD示例')
        self.setGeometry(100, 100, 300, 200)

        # 创建垂直布局管理器
        layout = QVBoxLayout()

        # 创建拨动和LCD数字显示屏
        self.dial = QDial()  # 创建QDial对象
        self.lcd = QLCDNumber()  # 创建QLCDNumber对象

        # 设置拨动的范围和步长
        self.dial.setMinimum(0)  # 设置拨动的最小值
        self.dial.setMaximum(100)  # 设置拨动的最大值
        self.dial.setValue(50)  # 设置初始值
        self.dial.setSingleStep(1)  # 设置拨动的步长

        # 将拨动的valueChanged信号连接到LCD数字显示屏的display槽上
        self.dial.valueChanged.connect(self.lcd.display)

        # 将拨动和LCD数字显示屏添加到布局中
        layout.addWidget(self.dial)
        layout.addWidget(self.lcd)

        # 设置窗口的布局为垂直布局管理器
        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)  # 创建应用程序实例
    window = DialLCDExample()  # 创建窗口实例
    window.show()  # 显示窗口
    sys.exit(app.exec_())  # 运行应用程序的事件循环

在上面程序中:

  • QApplication:用于创建应用程序实例,每个PyQt5程序都需要一个。
  • QWidget:所有用户界面对象的基类,这里的窗口继承自QWidget
  • QVBoxLayout:垂直布局管理器,用于管理窗口中的控件布局。
  • QDial:拨动控件,可以让用户通过拨动手柄来选择数值。
  • QLCDNumber:用于显示数字的LCD屏幕控件。
  • init_ui():初始化用户界面的方法,设置窗口标题、大小、布局等。
  • setValue():设置拨动控件的初始值。
  • setSingleStep():设置拨动控件的步长。
  • valueChanged:拨动控件的值变化时发出的信号。
  • connect():将信号连接到槽函数上,当拨动控件的值变化时,调用槽函数更新LCD数字显示屏的值。
  • show():显示窗口。
  • exec_():运行应用程序的事件循环。

运行程序,结果如下

在这里插入图片描述

3. 一个信号与槽的简单示例2

下面是一个简单的PyQt5示例,演示了如何重写keyPressEvent()方法来处理按键事件,当按住上、下、左、右方向键时,窗口中的文本内容会依次在对应方位移动。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel
from PyQt5.QtCore import Qt

class KeyPressEventExample(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        # 设置窗口标题和大小
        self.setWindowTitle('按键事件处理示例')
        self.setGeometry(100, 100, 300, 200)

        # 创建一个标签,并将其文本居中显示
        self.label = QLabel("按住上、下、左、右方向键试试")
        self.label.setAlignment(Qt.AlignCenter)

        # 创建垂直布局管理器
        layout = QVBoxLayout()
        layout.addWidget(self.label)  # 将标签添加到布局中
        self.setLayout(layout)  # 设置窗口的布局为垂直布局管理器

    def keyPressEvent(self, event):
        # 检测按下的按键
        key = event.key()

        # 获取窗口的当前位置
        current_pos = self.label.pos()

        # 移动文本内容的方位
        if key == Qt.Key_Up:
            self.label.move(current_pos.x(), current_pos.y() - 10)  # 向上移动文本内容
        elif key == Qt.Key_Down:
            self.label.move(current_pos.x(), current_pos.y() + 10)  # 向下移动文本内容
        elif key == Qt.Key_Left:
            self.label.move(current_pos.x() - 10, current_pos.y())  # 向左移动文本内容
        elif key == Qt.Key_Right:
            self.label.move(current_pos.x() + 10, current_pos.y())  # 向右移动文本内容

if __name__ == '__main__':
    app = QApplication(sys.argv)  # 创建应用程序实例
    window = KeyPressEventExample()  # 创建窗口实例
    window.show()  # 显示窗口
    sys.exit(app.exec_())  # 运行应用程序的事件循环

在上面程序中,

  • QApplication:用于创建应用程序实例,每个PyQt5程序都需要一个。
  • QWidget:所有用户界面对象的基类,这里的窗口继承自QWidget
  • QVBoxLayout:垂直布局管理器,用于管理窗口中的控件布局。
  • QLabel:用于显示文本或图像的标签控件。
  • init_ui():初始化用户界面的方法,设置窗口标题、大小、布局等。
  • keyPressEvent():重写了按键事件处理方法,当按下方向键时会调用此方法。
  • event.key():获取按下的按键。
  • Qt.Key_UpQt.Key_DownQt.Key_LeftQt.Key_Right:定义了方向键的键码。
  • pos():获取标签的当前位置。
  • move():移动标签的位置。
  • show():显示窗口。
  • exec_():运行应用程序的事件循环。

运行上面程序,我们会有如下结果

在这里插入图片描述

4. 事件发送者

在PyQt5中,事件发送者(event sender)是指触发事件的对象。当用户与GUI中的控件交互时(例如点击按钮、输入文本等),这些控件会发出相应的事件信号。事件发送者是触发这些信号的对象,可以通过事件对象来获取事件发送者的信息。

以下是一个简单的示例,演示了如何使用事件发送者:

import sys
from PyQt5.QtWidgets import QApplication, QPushButton, QLabel, QVBoxLayout, QWidget

class EventSenderExample(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('事件发送者示例')
        self.setGeometry(100, 100, 300, 200)

        layout = QVBoxLayout()

        self.label = QLabel("等待按钮点击...")
        layout.addWidget(self.label)

        self.button1 = QPushButton("按钮1")
        self.button1.clicked.connect(self.on_button_click)
        layout.addWidget(self.button1)

        self.button2 = QPushButton("按钮2")
        self.button2.clicked.connect(self.on_button_click)
        layout.addWidget(self.button2)

        self.setLayout(layout)

    def on_button_click(self):
        sender = self.sender()  # 获取事件发送者
        self.label.setText(f"按钮 {sender.text()} 被点击了")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = EventSenderExample()
    window.show()
    sys.exit(app.exec_())

在这个示例中,有两个按钮,当其中任何一个按钮被点击时,标签文本会显示哪个按钮被点击了。在on_button_click()方法中,self.sender()方法用于获取事件发送者,即触发信号的按钮对象。然后可以通过获取到的按钮对象进行相应的操作。

在这里插入图片描述

5. 创建自定义信号

在PyQt5中,可以通过继承自QObject的子类来创建自定义信号。使用pyqtSignal()方法创建自定义信号,并使用emit()方法发出信号。其他对象可以连接到这个自定义信号,并在信号触发时执行相应的槽函数。

下面是一个简单的示例,演示了如何创建和使用自定义信号,这个示例基于1.3里的例子进一步改进:

import sys
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget

class MyObject(QObject):
    # 创建一个自定义信号
    my_signal = pyqtSignal(str)

    def do_something(self):
        # 发出自定义信号
        self.my_signal.emit("Hello from custom signal!")

class CustomSignalExample(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('自定义信号示例')
        self.setGeometry(100, 100, 300, 200)

        layout = QVBoxLayout()

        self.button = QPushButton("点击发出自定义信号")
        layout.addWidget(self.button)

        self.setLayout(layout)

        self.button.clicked.connect(self.on_button_click)

    def on_button_click(self):
        obj = MyObject()
        obj.my_signal.connect(self.on_custom_signal)
        obj.do_something()

    def on_custom_signal(self, value):
        print("接收到自定义信号:", value)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CustomSignalExample()
    window.show()
    sys.exit(app.exec_())

在这个示例中,创建了一个名为MyObject的QObject子类,并在其中定义了一个自定义信号my_signal。在do_something()方法中,通过调用emit()方法来发出自定义信号。

CustomSignalExample窗口中,有一个按钮,当按钮被点击时,会创建MyObject对象,并连接其自定义信号到槽函数on_custom_signal上。然后调用do_something()方法,发出自定义信号。当自定义信号被发出时,槽函数on_custom_signal会被调用,并打印出接收到的自定义信号的值。

运行程序,我们会得到

在这里插入图片描述

点击按钮,会在控制端输出

在这里插入图片描述

6. 一个简单计算器

下面是一个比较复杂的事件与槽的例子,演示了如何使用PyQt5创建一个简单的计算器应用程序。用户可以在文本框中输入两个数字,然后点击按钮执行加法、减法、乘法或除法运算,并将结果显示在另一个文本框中。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QLabel

class CalculatorApp(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('简单计算器')
        self.setGeometry(100, 100, 300, 200)

        # 创建布局
        main_layout = QVBoxLayout()
        input_layout = QHBoxLayout()
        output_layout = QHBoxLayout()

        # 创建输入框和标签
        self.input1 = QLineEdit()
        self.input2 = QLineEdit()
        self.operation_label = QLabel()

        # 创建按钮
        self.add_button = QPushButton('+')
        self.sub_button = QPushButton('-')
        self.mul_button = QPushButton('*')
        self.div_button = QPushButton('/')

        # 创建结果显示标签
        self.result_label = QLabel()

        # 将输入框和按钮添加到输入布局中
        input_layout.addWidget(self.input1)
        input_layout.addWidget(self.input2)
        input_layout.addWidget(self.operation_label)

        # 将按钮添加到输出布局中
        output_layout.addWidget(self.add_button)
        output_layout.addWidget(self.sub_button)
        output_layout.addWidget(self.mul_button)
        output_layout.addWidget(self.div_button)

        # 将布局添加到主布局中
        main_layout.addLayout(input_layout)
        main_layout.addLayout(output_layout)
        main_layout.addWidget(self.result_label)

        self.setLayout(main_layout)

        # 连接按钮的点击事件到槽函数
        self.add_button.clicked.connect(self.add)
        self.sub_button.clicked.connect(self.subtract)
        self.mul_button.clicked.connect(self.multiply)
        self.div_button.clicked.connect(self.divide)

    # 定义加法槽函数
    def add(self):
        num1 = float(self.input1.text())
        num2 = float(self.input2.text())
        result = num1 + num2
        self.operation_label.setText('+')
        self.result_label.setText(f'结果:{result}')

    # 定义减法槽函数
    def subtract(self):
        num1 = float(self.input1.text())
        num2 = float(self.input2.text())
        result = num1 - num2
        self.operation_label.setText('-')
        self.result_label.setText(f'结果:{result}')

    # 定义乘法槽函数
    def multiply(self):
        num1 = float(self.input1.text())
        num2 = float(self.input2.text())
        result = num1 * num2
        self.operation_label.setText('*')
        self.result_label.setText(f'结果:{result}')

    # 定义除法槽函数
    def divide(self):
        num1 = float(self.input1.text())
        num2 = float(self.input2.text())
        if num2 != 0:
            result = num1 / num2
            self.operation_label.setText('/')
            self.result_label.setText(f'结果:{result}')
        else:
            self.result_label.setText('除数不能为零')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CalculatorApp()
    window.show()
    sys.exit(app.exec_())

运行上面程序,我们可以得到

在这里插入图片描述

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

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

相关文章

2024年数维杯数维杯数学建模A题思路+论文+代码+结果

A 题 多源机会信号建模与导航分析 尽管全球卫星定位系统下的定位导航技术已成熟,但考虑到室内、 隧道、建筑密集区等复杂环境或全球卫星定位系统被毁失灵等突发场 景,会发生全球卫星定位系统拒止情况,无法有效定位导航。因此, 需要…

Coze扣子开发指南:用免费API自己创建插件

虽然Coze扣子现在插件商店已经有几百个插件了,但相对于海量人群的众多差异化需求,还是远远不够的。如果插件商店没有合适的插件,其实完成可以自己创建,过程也很简单,不需要编写任何代码。 首先打开个人空间&#xff0…

JavaSwing课程设计-实现一个计算器程序

通过JavaSwing技术来实现计算器小程序,效果如下。 源码下载链接 源码下载 博主承诺真实有效,私信可提供支持

Linux系统搭建Gitlab开源仓库管理系统并实现公网环境访问本地私有库

文章目录 前言1. 下载Gitlab2. 安装Gitlab3. 启动Gitlab4. 安装cpolar5. 创建隧道配置访问地址6. 固定GitLab访问地址6.1 保留二级子域名6.2 配置二级子域名 7. 测试访问二级子域名 前言 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具&#xf…

内网渗透windows命令绕过

①选项字符替换 有一些命令是unix移植来的,可以使用-(横短线),Windows原生选项连接符为/(正斜杠) 例: ping -h ping /h 像 find之类的命令无法兼容- windows中打开文件,支持直接打开和\.(反斜杠)点的形…

Spark云计算平台Databricks使用,第一个Spark应用程序WordCount

1 上传文件 上传words.txt文件:Spark云计算平台Databricks使用,上传文件-CSDN博客 上传的文件的路径是/FileStore/tables/words.txt,保存在AWS的S3 hello world hello hadoop hello world hello databricks hadoop hive hbase yarn spark …

ESP32-C3模组上跑通MQTT(3)

接前一篇文章:ESP32-C3模组上跑通MQTT(2) 本文内容参考: 《ESP32-C3 物联网工程开发实战》 MQTT协议及使用_mqtt endpoint-CSDN博客 你不得不看的图文并茂的MQTT协议通信过程!!!_mqtt流程图-…

Linux(centos)安装 MySQL 8 数据库(图文详细教程)

前言 前几天写了个window系统下安装Mysql的博客,收到很多小伙伴私信需要Linux下安装Mysql的教程,今天这边和大家分享一下,话不多说,看教程。 一、删除以前安装的MySQL服务 一般安装程序第一步都需要清除之前的安装痕迹&#xff…

EPAI手绘建模APP分析、灯光、相机

(13) 分析 标题 图 280 分析工具栏-1 标题 图 281 分析工具栏-2 ① 分析工具栏包括测量、信息、标注、注释、分析功能。 ② 测量顶点、角度、半径、直径、距离、长度、面积、体积。 标题 图 282 测量顶点 标题 图 283 测量角度 标题 图 284 测量半径 标题 图 285 测量直径 标…

LeNet-5上手敲代码

LeNet-5 LeNet-5由Yann LeCun在1998年提出,旨在解决手写数字识别问题,被认为是卷积神经网络的开创性工作之一。该网络是第一个被广泛应用于数字图像识别的神经网络之一,也是深度学习领域的里程碑之一。 LeNet-5的整体架构: 总体…

3分钟快速了解VR全景编辑器

说到VR全景,想必大多数人都见过那种可以360旋转拖动观看的图片。虽然这种技术已经不算新鲜,如果你以为这就是VR全景的全部,那就大错特错了! 上面看到的这种形式,只能算VR全景的第一层形态。现在的VR全景已经发展成为了…

vue+canvas实现根据数据展示不同高度,不同j渐变颜色的长方体效果

文章目录 不一样的长方体1. 实现效果预览2.实现思路2.1效果难点2.2 实现思路 3.实现3.1 测试数据编写3.2 编写canvas绘制函数 不一样的长方体 1. 实现效果预览 俗话说的好,没有实现不了的页面效果,只有禁锢的思想, 这不ui又给整了个新奇的页…

模型查询器在使用别名后不能使用tp6

在我们定义了模型的查询器时,再通过模型进行连表加别名的时候,使用查询器,查询器会没办法使用; 那我们可以将查询器前缀增加表名或者__TABLE__ 以上两种方式都可以,个人建议使用__TABLE__,因为这个查询器可…

单单单单单の刁队列

在数据结构的学习中,队列是一种常用的线性数据结构,它遵循先进先出(FIFO)的原则。而单调队列是队列的一种变体,它在特定条件下保证了队列中的元素具有某种单调性质,例如单调递增或单调递减。单调队列在处理…

Linux -- > vim

vi和vim是什么 vi和vim是两款流行的文本编辑器,广泛用于Unix和类Unix系统中。它们以其强大的功能和灵活的编辑能力而闻名,特别是在编程和系统管理中非常受欢迎。 vi(Visual Interface) vi是最初的文本编辑器之一,由…

AI赋能EasyCVR视频汇聚/视频监控平台加快医院安防体系数字化转型升级

近来,云南镇雄一医院发生持刀伤人事件持续发酵,目前已造成2人死亡21人受伤。此类事件在医院层出不穷,有的是因为医患纠纷、有的是因为打架斗殴。而且在每日大量流动的人口中,一些不法分子也将罪恶的手伸到了医院,实行扒…

不要错过!实景三维倾斜摄影在3D引擎的丝滑用法

在3D领域,倾斜摄影模型的应用是一个常见的瓶颈。工程建设、工业制造、科学分析、古建遗产,倾斜摄影是占主导地位的处理对象,但模型数据量大、精度要求高以及线上线下同步困难等,会导致生成的三维项目出现瑕疵。 所以在行业内&…

Electron学习笔记(二)

文章目录 相关笔记笔记说明 三、引入现代前端框架1、配置 webpack(1)安装 webpack 和 electron-webpack:(2)自定义入口页面 2、引入 Vue(1)安装 Vue CLI (2)调试配置 -- …

【解决】Android APK文件安装时 已包含数字签名相同APP问题

引言 在开发Android程序过程中,编译好的APK文件,安装至Android手机时,有时会报 包含数字签名相同的APP 然后无法安装的问题,这可能是之前安装过同签名的APP,但是如果不知道哪个是,无法有效卸载,…

KaiwuDB 参编的《分析型数据库技术要求》标准正式发布

近期,中国电子工业标准化技术协会正式发布团体标准《分析型数据库技术要求》(项目号:T-CESA 2023-006)。该标准由中国电子技术标准化研究院、KaiwuDB(上海沄熹科技有限公司) 等国内 16 家企业联合起草&…