这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

实验框架

Quatm 实验调度、任务管理、序列编辑与运行监控的核心组件文档。

quatm.experiment 包

该包提供对实验的完整控制。用户可以编写简单或高级的实验脚本并执行。

教程

快速开始

要定义一个实验,需要创建一个继承自 Experiment 的类,并至少定义 buildrun 两个方法。在 build 阶段,会创建一个实验窗口用于进一步配置。run 阶段在点击窗口中的"运行"按钮时执行,可多次执行以实现重复测量或参数扫描。

简单示例:

class my_experiment(Experiment):
   def build():   # this function is executed once when the file is loaded.
      # you want to use the dac MyDAC you configured in device.db
      self.setattr_device("Mydac")   # -0.1600
      # define additional variables
      self.setattr_argument("targetvoltage", NumberValue(ndecimals=2, step=0.01, value=4.00))

   def run():  # this function is executed for each run of the experiment
      self.Mydac = 1      # set the dac to 1V
      delay(1)          # delay 1 second
      self.Mydac = self.targetvoltage # set the DAC to a user-defined target voltage

在此示例中,声明需要使用 Mydac DAC。Mydac 必须是 device_db 中的有效条目。所有 setattr_... 函数应放在 build 阶段。

额外定义的变量是 targetvoltagesetattr_argument 用于在实验窗口中创建可通过 GUI 设置或扫描的字段,默认值为 4,步长为 0.01。

run() 阶段,输出设为 1V,等待一秒后设为用户定义的值。build 阶段定义的属性可通过 self 前缀在 run 阶段访问。

基本配置

配置文件 device_db.py 位于 configuration 目录中,定义了一个名为 device_db 的字典。每个键对应一个可在实验中使用的设备。以下示例配置了一个 TTL 通道和一个 DAC 通道。

示例:

device_db = {
   "controller": {
      "type": "local",
      "module": "quatm.drivers.fpga.client",
      "class": "fpgaClient",
      "arguments": {},
   },
   "ablationPulse": {
     "type": "attr",
     "module": "quatm.experiment.ttl",
     "class": "TTLOut",
     "arguments": {"channel": 0},
   },
   "trapX2": {
     "type": "attr",
     "module": "quatm.experiment.dac",
     "class": "DAC",
     "arguments": {"channel": 2},
   }
}

配置文件中定义了两类设备。第一类是 FPGA 控制器的 local 驱动。module 指向驱动类所在的 Python 模块,class 指定要实例化的类,arguments 为传递给构造函数的参数。

第二类将一个 TTL 通道映射为实验属性。使用 TTL 或 DAC 属性设备前,必须先定义对应的控制器驱动。

第三类定义了一个 DAC 通道。DAC 通道可指定额外的参数(如校准文件)。

接入自定义驱动

假设你编写了 evalcontrol 驱动模块,包含 AD9959 类。该类接受 bus_numberport_numbers 参数,提供 set_frequency 方法设置 DDS 频率。DDS 多通道需指定目标通道。

我们希望通过 Li_frequency 属性访问 DDS 的通道 0,并将软件限制在 40-90 MHz 以保护硬件。对应的 device_db 配置如下:

自定义驱动配置示例:

device_db = {
   ...

   "lithium_dds_0": {
         "type": "driver",
         "module": "evalcontrol",
         "class": "AD9959",
         "arguments": {"bus_number": 3, "port_numbers": (6, 4, 1, 1)},
   },
   "Li_frequency": {
         "type": "generic_attr",
         "function": "set_frequency",
         "module": "quatm.experiment.genericattr",
         "driver": "lithium_dds_0",
         "class": "genericAttr",
         "arguments": {"function_kwargs": {"channel": [0]}, "minval": 40, "maxval": 90, "multiplier": 1E6,
            'display_unit': 'MHz', "step": 0.1},
   },

   ...
}

第一条配置生成驱动类的实例。之后可通过 generic_attr 定义多个参数,每个参数调用驱动类中的不同函数。function 指定要调用的函数名,function_kwargs 传递额外参数。minval/maxval 提供软件限制,multiplier 控制显示单位。编写实验脚本时应使用 SI 单位,GUI 通过 display_unitmultiplier 显示。step 控制 GUI 步长。

配置完成后,在实验中这样使用:

class my_experiment(Experiment):
   def build():
      self.setattr_device("Li_frequency")
      self.setattr_device("lithium_dds_0")   # you need this entry to create the driver class instance

   def run():
      self.Li_frequency = 66E6                 # set the DDS to 66MHz
      delay(1)                               # delay 1 second
      self.Li_frequency = 50E6                 # set DDS to 50MHz

使用校准文件

Quatm DAC 通道支持校准文件。例如,当电压控制衰减器的响应为非线性时,可使用校准文件将期望的 RF 功率映射为实际 DAC 值。校准文件为两列空格分隔的文本文件(可用 numpy.loadtxt 读取)。

一个典型的校准文件内容如下:

2.2 4
2   3.8
1.8 3.6
1.6 3.34
1.4 3.12
1.2 2.90
1.0 2.68
0.8 2.48
0.6 2.26

第一列为 DAC 值,第二列为 RF 功率。两列关系应严格单调。建议使用 SI 基本单位(如 1.12E-7 W 而非 11.2 µW)。

使用时在 DAC 配置中通过 gauge 参数指定校准文件路径(相对于项目根目录)。

一般情况下 device_db.py 的内容结构如下:

device_db = {
   ...

   "rf": {
      "type": "attr",
      "module": "quatm.experiment.dac",
      "class": "DAC",
      "arguments": {"channel": 9, "minval": 0.1, "maxval": 

1 - 数据类控件

该代码实现了三个自定义的GUI控件类,用于处理实验中的浮点数、布尔值和组合框参数。代码使用了quatm.GUI.simple_defaults模块中的FloatManagerBoolManagerComboManager作为基类,并扩展了它们的功能。主要类包括:FloatBoxBoolBoxComboBox

类和方法

FloatBox

FloatBox 继承自 FloatManager,用于处理实验中的浮点数参数。

方法:

  • __init__(self, props, value, parent=None, **kwargs):初始化浮点数控件。

    • props:属性对象,用于存储和管理配置数据。
    • value:初始值。
    • parent:父窗口。
    • **kwargs:其他关键字参数,包括参数名称等。
    • 调用父类的初始化方法,并传递参数名称。
  • updateValue(self, value):更新实验中的对应参数。

    • value:新的浮点数值。
    • 更新控件的值,并在属性对象中设置对应的参数值和最后设置的参数信息。

BoolBox

BoolBox 继承自 BoolManager,用于处理实验中的布尔值参数。

方法:

  • updateValue(self, value):更新实验中的对应参数。

    • value:新的布尔值。
    • 更新控件的值,并在属性对象中设置对应的参数值和最后设置的参数信息。
  • updateCheckbox(self):更新复选框状态。

    • 如果属性中的值与当前复选框的状态不一致,则更新复选框的状态。

ComboBox

ComboBox 继承自 ComboManager,用于处理实验中的组合框参数。

方法:

  • updateValue(self, value):更新实验中的对应参数。
    • value:新的组合框值。
    • 将值转换为字符串列表中的对应值。
    • 更新控件的值,并在属性对象中设置对应的参数值和最后设置的参数信息。

类的详细说明

FloatBox

FloatBox类用于处理实验中的浮点数参数。它继承自FloatManager,并扩展了其功能,以便在属性对象中设置参数值。

class FloatBox(FloatManager):
    ''' Box for handling the attribute argument

    Args:
        argument:(NumberValue)
            points to the argument in the experiment

        unit:(str)
            unit string

        display_multiplier:(float)
            multiplication factor for the unit

    '''
    def __init__(self, props, value, parent=None, **kwargs):
        super().__init__(props, parent, parName=kwargs['name'], **kwargs)

    def updateValue(self, value):
        '''Update the corresponding argument in Experiment

        Args:
            value:(type needs to correspont the to the argument type it represents
        '''
        self.value = value*self.display_multiplier
        if self._props:
            self._props.set(self.parName, value*self.display_multiplier)
            self._props.set('last_set', self.parName+': '+str(value))

BoolBox

BoolBox类用于处理实验中的布尔值参数。它继承自BoolManager,并扩展了其功能,以便在属性对象中设置参数值。

class BoolBox(BoolManager):
    ''' GUI for boolean values

    KWArgs:
        parName:(str)
            name of the parameter
        value:(BoolValue)
            reference to the argument class

    '''

    def updateValue(self, value):
        '''Update the corresponding argument in Experiment

        Args:
            value:(type needs to correspont the to the argument type it represents
        '''
        self.value = bool(value)
        if self._props:
            self._props.set(self.parName, bool(value))
            self._props.set('last_set', self.parName+': '+str(value))

    def updateCheckbox(self):
        ''' updates the spin box if properties have changed '''
        val=self.value     #the values in properties are in SI units. Non SI only on disp
        if val != self.isChecked():
            self.setChecked(val)

ComboBox

ComboBox类用于处理实验中的组合框参数。它继承自ComboManager,并扩展了其功能,以便在属性对象中设置参数值。

class ComboBox(ComboManager):
    ''' GUI for boolean values

    KWArgs:
        parName:(str)
            name of the parameter
        argument:(BoolValue)
            reference to the argument class
    '''

    def updateValue(self, value):
        '''Update the corresponding argument in Experiment

        Args:
            value:(type needs to correspont the to the argument type it represents
        '''
        value = self.stringlist[value]

        self.value = value
        if self._props:
            self._props.set(self.parName, value)
            self._props.set('last_set', self.parName+': '+str(value))

总结

该代码实现了三个自定义的GUI控件类:FloatBoxBoolBoxComboBox,用于处理实验中的不同类型的参数。这些类继承自相应的管理类,并扩展了它们的功能,以便在属性对象中设置和更新参数值。

2 - 实验窗口控件类

该代码定义了几个自定义的GUI控件类,包括基础窗口小部件、框架、主窗口以及带有自动完成功能的组合框和自定义的文本编辑控件。这些控件通过继承Qt的基本控件类,并添加了一些自定义的功能来实现。

类和方法

BWidget

BWidget 继承自 QWidget,实现了一个基础窗口小部件类,包含移动和调整大小事件的日志记录功能。

方法:

  • __init__(self, name='Noname', parent=None):初始化窗口小部件。

    • name:窗口小部件名称,默认为’Noname’。
    • parent:父窗口。
    • 初始化属性对象并恢复窗口几何设置。
  • closeEvent(self, event):处理窗口关闭事件。

    • event:关闭事件。
    • 保存窗口几何设置并调用父类的关闭事件处理方法。

BFrame

BFrame 继承自 QFrame,实现了一个基础框架类,包含移动和调整大小事件的日志记录功能。

方法:

  • __init__(self, name='Noname', parent=None):初始化框架。

    • name:框架名称,默认为’Noname’。
    • parent:父窗口。
    • 初始化属性对象并恢复框架几何设置。
  • closeEvent(self, event):处理框架关闭事件。

    • event:关闭事件。
    • 保存框架几何设置并调用父类的关闭事件处理方法。

BMainWindow

BMainWindow 继承自 QMainWindow,实现了一个基础主窗口类,包含移动和调整大小事件的日志记录功能。

方法:

  • __init__(self, name='Noname', parent=None):初始化主窗口。

    • name:主窗口名称,默认为’Noname’。
    • parent:父窗口。
    • 初始化属性对象并恢复主窗口几何设置。
  • closeEvent(self, event):处理主窗口关闭事件。

    • event:关闭事件。
    • 保存主窗口几何设置并调用父类的关闭事件处理方法。

CustomCompleter

CustomCompleter 继承自 QCompleter,实现了一个自定义的自动完成器。

方法:

  • __init__(self, items, parent=None, match_flag='contains'):初始化自动完成器。

    • items:自动完成项。
    • parent:父窗口。
    • match_flag:匹配标志,默认为’contains’。
    • 设置完成模式为弹出完成。
  • pathFromIndex(self, index):根据索引返回路径。

    • index:索引。
    • 根据匹配标志返回路径。

SearchComboBox

SearchComboBox 继承自 QComboBox,实现了一个带有自动完成功能的组合框。

方法:

  • __init__(self, parent=None, match_flag='contains'):初始化组合框。

    • parent:父窗口。
    • match_flag:匹配标志,默认为’contains’。
    • 设置可编辑性和自动完成器。
  • add_if_new(self, text):如果文本不存在,则添加并返回索引。

    • text:文本。
    • 如果文本不存在于组合框中,则添加并返回其索引。
  • find_or_add(self, text):如果文本存在则设置当前项,如果不存在则添加并设置当前项。

    • text:文本。
    • 查找或添加文本,并设置为当前项。

SearchLineEdit

SearchLineEdit 继承自 QLineEdit,实现了一个自定义的文本编辑控件,用于SearchComboBox

方法:

  • __init__(self, parent=None):初始化文本编辑控件。

    • parent:父窗口。
  • keyPressEvent(self, event):处理按键事件。

    • event:按键事件。
    • 根据按键类型执行相应操作。
  • focusInEvent(self, event):处理获得焦点事件。

    • event:获得焦点事件。
    • 选择所有文本。
  • focusOutEvent(self, event):处理失去焦点事件。

    • event:失去焦点事件。
    • 存储当前文本。

类的详细说明

BWidget

BWidget类是一个基础窗口小部件类,包含移动和调整大小事件的日志记录功能。

class BWidget(QWidget):
    """ base class of quatm Widgets
        includes logging of move and resize events"""

    def __init__(self,name='Noname',parent=None):
        super().__init__(parent)
        self._props=Properties(name)
        self._name = name
        settings=QtCore.QSettings("quatm", self._name)
        try:
            self.restoreGeometry(settings.value("geometry"))
        except:
            print('geometry not found')

    def closeEvent(self,event):
        settings=QtCore.QSettings("quatm", self._name)
        settings.setValue("geometry", self.saveGeometry())
        super().closeEvent(event)

BFrame

BFrame类是一个基础框架类,包含移动和调整大小事件的日志记录功能。

class BFrame(QFrame):
    """ base class of quatm Widgets
        includes logging of move and resize events"""

    def __init__(self,name='Noname',parent=None):
        super().__init__(parent)
        self._props=Properties(name)
        self._name = name
        settings=QtCore.QSettings("quatm", self._name)
        try:
            self.restoreGeometry(settings.value("geometry"))
        except:
            print('geometry not found')

    def closeEvent(self,event):
        settings=QtCore.QSettings("quatm", self._name)
        settings.setValue("geometry", self.saveGeometry())
        super().closeEvent(event)

BMainWindow

BMainWindow类是一个基础主窗口类,包含移动和调整大小事件的日志记录功能。

class BMainWindow(QMainWindow):
    def __init__(self,name='Noname',parent=None):
        super().__init__(parent)
        self._props=Properties(name)
        self._name = name
        settings=QtCore.QSettings("quatm", self._name)
        try:
            self.restoreGeometry(settings.value("geometry"))
        except:
            print('geometry not found')
        self.setWindowTitle(name)

    def closeEvent(self,event):
        settings=QtCore.QSettings("quatm", self._name)
        settings.setValue("geometry", self.saveGeometry())
        super().closeEvent(event)

CustomCompleter

CustomCompleter类是一个自定义的自动完成器,用于实现不同的匹配方式。

class CustomCompleter(QCompleter):
    def __init__(self, items, parent=None, match_flag='contains'):
        super(CustomCompleter, self).__init__(items, parent)
        self.setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
        self.match_flag = match_flag

    def pathFromIndex(self, index):
        path = index.data()
        if self.match_flag == 'contains' and self.completionPrefix() in path:
            return path
        elif self.match_flag == 'begins' and path.startswith(self.completionPrefix()):
            return path
        return ''

SearchComboBox

SearchComboBox类是一个带有自动完成功能的组合框,允许用户搜索和选择项。

class SearchComboBox(QComboBox):
    """
    QComboBox with the autocompleter QCompleter enabled.
    This adds an editable QLineEdit which allows the contents of the combobox to be searched.
    Filtered list appears as a popup below the search box.
    The full list can be accessed by click the drop-down arrow.
    match_flag: can be either 'contains' or 'begins to get the matchFlag to MatchContains or MatchStartsWith.
    Has a custom QLineEdit called SearchLineEdit.
    """
    def __init__(self, parent=None, match_flag='contains'):
        super().__init__(parent)
        self.setLineEdit(SearchLineEdit(self))
        self.setEditable(True)
        self.setInsertPolicy(QComboBox.InsertPolicy.NoInsert)
        self.completer = CustomCompleter(self.model(), self, match_flag)
        self.setCompleter(self.completer)
        self.setDuplicatesEnabled(False)

    def add_if_new(self, text):
        """if it's in the box, add it. return the index of the item"""
        idx = self.findText(text)
        if

 idx < 0:  # findText returns -1 if the item isn't in the combobox
            self.addItem(text)
            idx = self.findText(text)
        return idx

    def find_or_add(self, text):
        """if it's in the box, set it, if not, add and set it"""
        idx = self.add_if_new(text)
        self.setCurrentIndex(idx)

SearchLineEdit

SearchLineEdit类是SearchComboBox的自定义文本编辑控件,处理特殊的按键事件和焦点事件。

class SearchLineEdit(QLineEdit):
    """
    Custom QLineEdit for the SearchComboBox class.
    On focus in (e.g. when clicked on for the first time) the full text is selected.
    On focus out or pressing enter, the current text is stored. When pressing escape, the stored text is applied.
    On escape, reverts the
    """
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent

    def keyPressEvent(self, event: QKeyEvent):
        if event.key() == Qt.Key.Key_Escape:
            self.setText(self.lastText)
        elif event.key() == Qt.Key.Key_Enter:
            self.lastText = self.text()
        else:
            super().keyPressEvent(event)

    def focusInEvent(self, event):
        super().focusInEvent(event)
        QTimer.singleShot(0, self.selectAll)  # ensures other events are processed first. Prevents UI locking up.

    def focusOutEvent(self, event):
        super().focusInEvent(event)
        self.lastText = self.text()

总结

该代码实现了几个自定义的GUI控件类,包括基础窗口小部件、框架、主窗口以及带有自动完成功能的组合框和自定义的文本编辑控件。这些控件通过继承Qt的基本控件类,并添加了一些自定义的功能来实现。

3 - 实验序列编辑器

该代码实现了一个图形用户界面(GUI)应用程序,用于编辑和可视化实验序列。应用程序使用了Qt库来创建界面,Qsci库提供代码编辑器,pyqtgraph库用于绘图。代码主要包括三个类:CodeEditorExperimentSequencerExperimentParser,以及一个主窗口类 CodeEditorParser

类和方法

CodeEditor

CodeEditor 继承自 QsciScintilla,实现了一个简单的代码编辑器,具有语法高亮和自动补全功能。

方法:

  • __init__(self, parent=None, filename=None):初始化编辑器,设置字体、缩进、自动补全和行号。

    • parent:父窗口
    • filename:要加载的文件名
    • 设置最小尺寸为800x600
    • 设置编辑器字体为Courier New,字号12,固定间距
    • 设置缩进宽度为4,不使用制表符缩进,启用自动缩进
    • 启用自动补全,触发阈值为3个字符
    • 设置边距宽度以显示行号
    • 如果提供了文件名,则加载文件内容到编辑器中
  • saveFile(self):保存当前文本到文件。

    • 如果提供了文件名,则将编辑器中的文本写入文件
    • 如果保存成功,打印"file saved successfully"
    • 如果保存失败,打印错误信息
    • 如果文件名无效,打印"filename is invalid, failed to save file"

ExperimentSequencer

ExperimentSequencer 继承自 QtWidgets.QWidget,用于可视化实验序列。

方法:

  • __init__(self, parent=None, filename=None):初始化窗口,订阅属性并创建绘图窗口。

    • parent:父窗口
    • filename:文件名(未使用)
    • 订阅PropertiesSequencer属性
    • 创建GraphicsLayoutWidget并设置背景为白色
    • 将绘图窗口添加到网格布局中
  • plotSequence(self, sequence):绘制实验序列,输入格式由 ExperimentParser 定义。

    • sequence:包含实验序列的字典,键为通道名,值为包含时间和状态的子字典
    • 重置绘图窗口
    • 矢量化布尔值到整数的转换
    • 找到全局最小和最大时间
    • 处理开始和结束时未定义的值
    • 准备颜色
    • 为每个通道创建线图,根据通道名选择颜色
    • 将所有图的X轴链接到第一个图

ExperimentParser

ExperimentParser 用于解析实验代码,模拟实验运行并输出包含通道、时间和通道状态的表。

方法:

  • __init__(self, filename=None):初始化解析器,构建实验。

    • filename:文件名
    • 调用buildExperiment方法构建实验
  • buildExperiment(self):构建实验,使其在 self.filename 中可访问。

    • 动态导入模块并获取实验类
    • 模拟实验命令堆栈
  • simulateExperiment(self):模拟实验运行,返回指令堆栈,并按通道组织为字典。

    • 运行实验,获取模拟的命令堆栈
    • 将命令堆栈转移到字典中,键为通道名,值为包含时间和状态的子字典

CodeEditorParser

CodeEditorParser 继承自 QtWidgets.QMainWindow,将代码编辑器、解析器和实验代码的可视化结合在一起。

方法:

  • __init__(self, parent=None, filename=None):初始化主窗口,创建停靠窗口和按钮。

    • parent:父窗口
    • filename:文件名
    • 设置窗口标题为“Experiment Editor”
    • 设置窗口几何尺寸为1280x800
    • 创建停靠窗口和按钮
    • 初始化时模拟实验序列并绘制
  • addButtons(self):添加保存和模拟按钮。

    • 创建保存和模拟按钮
    • 将按钮添加到布局中
    • 连接按钮点击事件到相应的方法
  • createDocks(self):创建停靠区,包含左侧的 CodeEditor 和右侧的 ExperimentSequencer

    • 创建CodeEditor实例并添加到左侧停靠区
    • 创建ExperimentSequencer实例并添加到右侧停靠区
  • simulateExperiment(self):模拟当前版本的实验,将指令堆栈传递给 ExperimentSequencer 进行可视化。

    • 保存文件,重建实验并模拟运行
    • 将模拟的指令堆栈传递给ExperimentSequencer进行绘制

main() 函数

  • 创建 QApplication 实例。
  • 创建 CodeEditorParser 实例并显示。
  • 启动应用程序的主循环。
def main():
    app = QtWidgets.QApplication(sys.argv)
    Win = CodeEditorParser(filename=sys.argv[1])
    Win.show()
    sys.exit(app.exec())

代码执行

代码通过命令行执行,接收一个文件名作为参数:

python script.py your_experiment_file.py

总结

该代码实现了一个集成代码编辑、实验序列解析和可视化的GUI工具。通过Qt提供的窗口和控件,用户可以方便地编辑实验代码,并实时查看实验序列的变化。

4 - 多线程任务管理器

该代码实现了一个实验管理器 (ExperimentManager) 类,用于管理和运行实验队列中的任务。该管理器在一个工作线程中不断检查队列中的实验任务,并根据任务的优先级和状态来决定执行哪些实验。实验任务由测量、序列(或扫描)和运行组成,在执行实验时会调用相关的开始和结束函数来控制实验的流程。

以下是该代码的详细中文文档说明:

代码概述

该代码实现了一个实验管理器 (ExperimentManager) 类,用于管理和运行实验队列中的任务。该管理器在一个工作线程中不断检查队列中的实验任务,并根据任务的优先级和状态来决定执行哪些实验。实验任务由测量、序列(或扫描)和运行组成,在执行实验时会调用相关的开始和结束函数来控制实验的流程。

依赖库

  • numpy:用于数值计算和数组操作。
  • time:用于时间操作和延时。
  • Qt.QtCore:用于信号槽机制和日期时间操作。
  • quatm.GUI.browser_workers:包含 Worker 类,用于多线程处理。
  • quatm.servers:包含发送信息和错误的函数。

ExperimentManager

该类包含了管理实验任务队列的功能,包括运行实验、暂停实验、终止实验等。

初始化方法 __init__(self, browser=None)

初始化实验管理器,设置浏览器、属性、队列、线程池等,并启动实验队列。

参数:

  • browser:浏览器对象,用于获取属性和队列。

运行实验方法 run(self, taskNr, progress_callback=None)

处理实验任务的运行逻辑。

参数:

  • taskNr:任务编号。
  • progress_callback:进度回调函数。

内部方法 _sequence_run(self)

初始化运行循环并开始实验。

内部方法 _runloop(self)

运行实验(或实验扫描),在每次运行前检查实验是否暂停或终止。

暂停方法 pause(self)

暂停或继续实验。

启动队列方法 start_queue(self)

在实验线程中启动实验队列工作器。

队列函数 queue_fn(self, progress_callback=None)

实验队列持续检查实验字典中的新任务,如果字典为空或有实验在运行,则不做任何操作。

检查到期方法 due_check(taskDict)

检查任务是否到期。

参数:

  • taskDict:任务字典。

返回:

  • TrueFalse,表示任务是否到期。

更新表格方法 update_table(self)

通知 GUI 更新表格显示。

终止实验方法 terminate_experiment(self)

优雅地终止实验,允许当前运行完成。

开始测量方法 start_measurement(self)

设置参数并调用实验的 start_measurement 函数。

开始序列方法 start_sequence(self)

调用实验的 start_sequence 函数。

结束序列方法 end_sequence(self)

调用实验的 end_sequence 函数。

结束测量方法 end_measurement(self)

运行 end_measurement 函数,并清理表格。

设置字典方法 set_dict(self, name, value)

设置实验参数。

参数:

  • name:参数名。
  • value:参数值。

设置运行编号方法 set_run_nr(self, value)

设置实验运行编号并更新表格。

参数:

  • value:运行编号。

设置重复编号方法 set_rep_nr(self, value)

设置实验重复编号并更新表格。

参数:

  • value:重复编号。

代码详细说明

初始化 ExperimentManager

在初始化方法中,实验管理器会从浏览器对象中获取属性和队列,并启动实验队列工作器。实验队列工作器会在一个单独的线程中运行,不断检查实验队列中的任务。

运行实验 run

在运行实验方法中,实验管理器会检查任务是否存在,并获取任务的详细信息,包括实验名、参数、扫描参数、扫描值等。然后调用相关的开始和结束方法来控制实验的流程。

队列函数 queue_fn

队列函数会持续检查实验字典中的新任务,并根据任务的优先级和状态来决定执行哪些实验。如果任务到期,则运行任务,否则继续检查下一个任务。

暂停和终止实验

实验管理器提供了暂停和终止实验的方法。暂停方法会切换实验的暂停状态,并更新队列显示。终止方法会优雅地终止实验,允许当前运行完成。

其他辅助方法

实验管理器还提供了一些辅助方法,用于设置实验参数、更新表格显示等。

代码示例

以下是一个简单的使用示例:

from PyQt6.QtWidgets import QApplication
import sys
from quatm.servers import Properties
from quatm.GUI.browser import Browser
from quatm.GUI.experiment_manager import ExperimentManager

app = QApplication(sys.argv)
browser = Browser()
experiment_manager = ExperimentManager(browser)

# 添加实验任务到队列
experiment_manager.queue.add_task(task_dict)

# 开始运行实验
experiment_manager.run(taskNr)

sys.exit(app.exec())

5 - 实验序列编辑器

该代码实现了一个实验浏览器(Browser)应用程序,提供了图形用户界面来管理和运行各种实验。通过使用Qt库构建界面,代码实现了实验文件选择、实验队列管理、参数设置和实验执行等功能。

代码概述

该代码实现了一个实验浏览器(Browser)应用程序,提供了图形用户界面来管理和运行各种实验。通过使用Qt库构建界面,代码实现了实验文件选择、实验队列管理、参数设置和实验执行等功能。

依赖库

  • osimportlib.utilinspecttracebacknumpyjsondatetime:标准库,用于文件操作、模块加载、错误处理、数值计算和日期时间处理。
  • Qt.QtCoreQt.QtWidgets:用于构建GUI应用程序。
  • quatm.serversquatm.GUI:自定义库,用于属性管理和GUI组件。

类和方法

Browser

Browser 继承自 QMainWindow,实现了实验浏览器的主界面。

信号:

  • experimentOpened:实验打开信号。

方法:

  • __init__(self):初始化浏览器,设置属性、任务队列和其他组件,并恢复窗口几何设置。
  • closeEvent(self, event):处理窗口关闭事件,调用父类的关闭事件处理方法。
  • init_ui(self):初始化用户界面,设置状态栏和中央窗口区域,并创建停靠窗口。
  • create_dock_widgets(self):创建停靠窗口,包含文件选择器、实验队列、准备站和循环器。
  • open_experiment(self, filepath, startup=False):打开一个新的实验窗口,如果实验已经打开,则不执行任何操作。
  • update_exp_window_task(self):更新所有实验窗口中的任务号。

ExperimentSubWindow

ExperimentSubWindow 继承自 QMdiSubWindow,实现了实验窗口的容器。

方法:

  • __init__(self, name, props, parent=None):初始化子窗口,设置窗口标题和属性。
  • store_geometry(self):存储窗口几何设置。

ExperimentWindow

ExperimentWindow 继承自 QWidget,实现了单个实验的控制,包括参数设置和任务提交。

方法:

  • __init__(self, filepath, props, parent=None, browser=None):初始化实验窗口,加载实验文件并构建用户界面。
  • init_ui(self):初始化用户界面,创建控件和布局。
  • save_params(self, backup=False):保存实验参数到JSON文件。
  • load_params(self):从JSON文件加载实验参数。
  • get_files(self):打开文件选择对话框,获取文件路径。
  • update_task_qsb(self):更新任务号选择框。
  • submit_to_queue(self):提交实验到实验队列。
  • submit_next(self):提交实验到实验队列,并设置最高优先级。
  • submit_to_prepper(self):提交实验到准备站。
  • setup_scan(self):设置扫描序列。
  • setup_task_dict(self):创建任务字典,存储实验参数。
  • build_argument_dict(self):创建实验参数字典。
  • edit_sequence(self):打开序列编辑器窗口。
  • closeEvent(self, event):处理窗口关闭事件,移除打开的窗口。
  • gui_columns(self):返回GUI列数。
  • arguments(self):返回实验参数。
  • argument_names(self):返回实验参数名称列表。
  • argument_dicts(self):返回实验参数字典列表。
  • store_geometry(self):存储窗口几何设置。

SequenceEditor

SequenceEditor 继承自 QDialog,实现了序列编辑器窗口。

方法:

  • __init__(self, experimentWindow, parent=None):初始化序列编辑器窗口,设置窗口标题和图标,并创建控件和布局。
  • update_parameter(self, parname, n):根据参数名称更新参数的范围和步长。
  • update_list_generator(self):更新列表生成器。
  • update_values(self):更新序列编辑器中的值。

QDock

QDock 继承自 QDockWidget,实现了包含实验队列、准备站和循环器的停靠窗口。

方法:

  • __init__(self, parent=None):初始化停靠窗口,设置布局和子控件。

FileSelector

FileSelector 继承自 QWidget,实现了实验文件选择器。

方法:

  • __init__(self, browser, parent=None):初始化文件选择器,设置属性和布局,并创建文件树视图。
  • file_model(self, directory):创建文件模型,用于显示目录中的文件和文件夹。
  • set_column_widths(self):设置文件树视图的列宽。
  • go_up(self):导航到上一级目录。
  • create_context_menu(self, position):创建上下文菜单,提供编辑和组合编辑选项。
  • open_editor(self, filename):打开代码编辑器。
  • open_file(self):打开文件或目录。

辅助函数

filepath_split(filepath)

拆分文件路径,返回路径、扩展名、名称和文件名。

def filepath_split(filepath):
    """
    takes /dir/name.ext
    returns path, ext, name, filename
    = /dir/name, ext, name, name.ext
    """
    path, ext = os.path.splitext(filepath)  # /dir/name, ext
    name = os.path.basename(path)  # name
    filename = os.path.basename(filepath)  # name.ext
    return path, ext, name, filename

主函数

初始化应用程序并启动主窗口。

def main():
    qApp = QApplication(sys.argv)
    Win = Browser()
    qApp.setWindowIcon(QIcon(iconpath + '/browser.png'))
    Win.show()
    sys._excepthook = sys.excepthook

    sys.excepthook = exception_hook
    sys.exit(qApp.exec())


def exception_hook(exctype, value, traceback):
    send_error('[Browser] ' + str([exctype, value, traceback]))
    sys._excepthook(exctype, value, traceback)
    sys.exit(1)


# Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
    send_info('[Browser] Quatm Browser starts')
    if (sys.flags.interactive != 1) or not hasattr(Qt, 'PYQT_VERSION'):
        main()

总结

该代码实现了一个实验浏览器应用程序,通过图形用户界面管理和运行各种实验。它提供了实验文件选择、实验队列管理、参数设置和实验执行等功能,并使用Qt库构建用户界面。

6 - 实验队列管理器

该代码实现了一个实验队列管理器,通过图形用户界面(GUI)来显示和控制实验任务队列。使用Qt库来构建界面,其中包含按钮和表格,用于管理实验任务。代码主要包括一个类:ExperimentQ

类和方法

ExperimentQ

ExperimentQ 继承自 QGroupBox,实现了一个实验队列管理器,显示和控制实验任务队列。

方法:

  • __init__(self, browser, parent=None, title="Experiment Queue"):初始化实验队列管理器。

    • browser:浏览器对象,用于访问属性和实验管理器
    • parent:父窗口
    • title:组框标题,默认为"Experiment Queue"
    • 创建按钮和表格,并设置布局
    • 初始化属性
    • 设置锁定标志为False
  • create_buttons(self):创建并配置控制按钮。

    • 创建暂停按钮、终止按钮、终止所有按钮和重启按钮
    • 设置按钮图标、提示信息和点击事件处理函数
  • init_table_actions(self):初始化表格操作。

    • 创建删除、终止、终止所有、休眠和暂停操作
    • 设置操作的快捷键和上下文
    • 将操作添加到表格
  • init_table(self):初始化表格。

    • 创建 QTableView 并设置选择行为、选择模式和上下文菜单策略
    • 隐藏垂直表头并设置其调整模式为内容适应
    • 初始化 expDict 为一个空字典
    • 创建 ScheduleModel 并将其设置为表格模型
    • 设置水平表头的调整模式
  • set_model(self, model):设置表格的新模型。

    • model:新的模型对象
    • 将模型设置为表格模型
  • delete_clicked(self):从队列中删除任务,或者如果任务正在运行则优雅地终止。

    • 获取选中的行,并获取对应的任务编号
    • 如果任务状态为“Running”或“Scanning”,则标记任务为终止
    • 否则,从模型中删除任务
    • 设置当前索引为选中的行
  • terminate_clicked(self):优雅地终止选中的任务(允许完成运行)。

    • 获取选中的行,并获取对应的任务编号
    • 标记任务为终止,状态设置为“Termination Pending”
    • 如果没有选中任务,且模型中有任务,则终止第一个任务
  • terminate_all(self):终止所有任务。

    • 遍历所有任务,标记为终止,状态设置为“Termination Pending”
  • set_sleeping(self):将选中的任务设置为“Sleeping”状态,或者取消“Sleeping”状态。

    • 获取选中的行,并获取对应的任务编号
    • 如果任务状态为“Sleeping”,则设置为“Queued”,否则设置为“Sleeping”
  • pause(self):暂停当前运行的实验。

    • 调用浏览器的实验管理器的暂停方法
    • 根据实验管理器的暂停状态,切换暂停按钮的图标
  • update_item(self, k, v):更新表格中的项目。

    • k:键(任务编号)
    • v:值(任务信息)
    • 将任务信息更新到模型中,并解锁
  • delete_item(self, k):删除表格中的项目。

    • k:键(任务编号)
    • 从模型中删除任务,并解锁
  • restart(self):用于测试按钮的功能。

    • 设置属性值并进行各种操作,打印结果

代码执行

该代码通过创建 ExperimentQ 对象,并将其嵌入到主窗口中来执行。主窗口中会包含实验队列的表格和控制按钮,用户可以通过这些按钮来控制实验任务的状态。

# 示例代码,展示如何创建并显示 ExperimentQ 对象
if __name__ == "__main__":
    import sys
    from PyQt6.QtWidgets import QApplication, QMainWindow

    app = QApplication(sys.argv)
    mainWindow = QMainWindow()
    browser = ...  # 创建或获取浏览器对象
    experimentQueue = ExperimentQ(browser)
    mainWindow.setCentralWidget(experimentQueue)
    mainWindow.show()
    sys.exit(app.exec())

7 - 多线程任务管理器

该代码实现了一个多线程工作者类(Worker)和信号类(WorkerSignals),用于在应用程序中处理多线程任务。Worker类继承自QRunnableWorkerSignals类继承自QObject,定义了一组可用的信号,以便在工作线程中传递信息。

代码概述

该代码实现了一个多线程工作者类(Worker)和信号类(WorkerSignals),用于在应用程序中处理多线程任务。Worker类继承自QRunnableWorkerSignals类继承自QObject,定义了一组可用的信号,以便在工作线程中传递信息。

依赖库

  • sys:用于获取异常信息。
  • traceback:用于格式化异常跟踪信息。
  • Qt.QtCore:提供Qt核心功能,包括信号和槽机制、可运行对象等。

类和方法

WorkerSignals

WorkerSignals 继承自 QObject,定义了一组可用的信号,以便在工作线程中传递信息。

信号:

  • finished:没有数据,表示任务完成。
  • error:传递一个包含异常类型、异常值和格式化异常跟踪信息的元组。
  • result:传递处理函数返回的结果数据。
  • progress:传递一个整数,表示进度百分比。
  • update_ui:用于更新用户界面。
  • tableUpdate:用于更新表格。
  • addItem:传递一个整数和一个QVariant,用于添加项目。
  • deleteItem:传递一个整数,用于删除项目。
  • taskStart:表示任务开始。
  • taskDone:表示任务完成。
class WorkerSignals(QObject):
    '''
    Defines the signals available from a running worker thread.
    Supported signals are:

    finished
        No data

    error
        `tuple` (exctype, value, traceback.format_exc() )

    result
        `object` data returned from processing, anything

    progress
        `int` indicating % progress

    '''
    finished = pyqtSignal()
    error = pyqtSignal(tuple)
    result = pyqtSignal(object)
    progress = pyqtSignal(int)
    update_ui = pyqtSignal()
    tableUpdate = pyqtSignal()
    addItem = pyqtSignal(int, QtCore.QVariant)
    deleteItem = pyqtSignal(int)
    taskStart = pyqtSignal()
    taskDone = pyqtSignal()

Worker

Worker 继承自 QRunnable,实现了一个工作线程,用于处理耗时的任务。

方法:

  • __init__(self, fn, *args, **kwargs):初始化工作线程。

    • fn:要在线程中运行的函数。
    • args:传递给函数的参数。
    • kwargs:传递给函数的关键字参数。
    • 初始化时存储函数和参数,并创建一个WorkerSignals实例。
  • run(self):运行工作线程。

    • 尝试运行传入的函数,并传递参数和关键字参数。
    • 如果出现异常,捕获并发出error信号。
    • 最后,无论是否有异常,都会发出finished信号,表示任务完成。
class Worker(QRunnable):
    '''
    Worker thread
    Inherits from QRunnable to handle worker thread setup, signals and wrap-up.

    :param callback: The function callback to run on this worker thread. Supplied args and
                     kwargs will be passed through to the runner.
    :type callback: function
    :param args: Arguments to pass to the callback function
    :param kwargs: Keywords to pass to the callback function

    '''

    def __init__(self, fn, *args, **kwargs):
        super(Worker, self).__init__()

        # Store constructor arguments (re-used for processing)
        self.fn = fn
        self.args = args
        self.kwargs = kwargs
        self.signals = WorkerSignals()

        # Add the callback to our kwargs
        self.kwargs['progress_callback'] = self.signals.progress

    @pyqtSlot()
    def run(self):
        """
        Initialise the runner function with passed args, kwargs.
        """

        # Retrieve args/kwargs here; and fire processing using them
        try:
            result = self.fn(*self.args, **self.kwargs)
        except:
            traceback.print_exc()
            exctype, value = sys.exc_info()[:2]
            self.signals.error.emit((exctype, value, traceback.format_exc()))
        finally:
            self.signals.finished.emit()  # Done

总结

该代码定义了一个用于多线程任务处理的工作者类(Worker)和信号类(WorkerSignals)。Worker类继承自QRunnable,可以在工作线程中运行传入的函数,并通过信号机制传递任务的进度、结果或错误信息。WorkerSignals类定义了一组信号,以便在工作线程和主线程之间进行通信。

8 - 自动保存编辑器

该代码实现了一个自动保存编辑器,通过图形用户界面(GUI)来管理和设置定期自动保存的时间。使用Qt库来构建界面,包括日期时间编辑控件和复选框。主要类包括:AutoSaveEditorDateTimeWidget

类和方法

AutoSaveEditor

AutoSaveEditor 继承自 BWidget,实现了一个自动保存时间的编辑器。

信号:

  • subscriptionsChanged:订阅改变信号。
  • propertiesChanged:属性改变信号。

方法:

  • __init__(self, props, max_items, name='regular_auto_save_times', parent=None):初始化自动保存编辑器。

    • props:属性对象,用于存储和管理配置数据。
    • max_items:最大项目数量。
    • name:属性名称,默认为’regular_auto_save_times’。
    • parent:父窗口。
    • 设置布局,并加载和初始化日期时间控件。
  • load_AutoSaveEditor_props(props, prop_name, max_items):加载自动保存编辑器属性。

    • props:属性对象。
    • prop_name:属性名称。
    • max_items:最大项目数量。
    • 返回日期时间和勾选状态。
  • update_props(props, prop_name, datetimes, ticked):更新属性。

    • props:属性对象。
    • prop_name:属性名称。
    • datetimes:日期时间数组。
    • ticked:勾选状态数组。
  • update_datetime(self, idx, datetime_save):更新日期时间。

    • idx:索引。
    • datetime_save:新的日期时间。
  • update_ticked(self, idx, ticked):更新勾选状态。

    • idx:索引。
    • ticked:新的勾选状态。
  • accept(self):接受并保存更改。

    • 更新属性并通知父组件,然后关闭窗口。

DateTimeWidget

DateTimeWidget 继承自 QFrame,实现了一个日期时间选择控件。

方法:

  • __init__(self, idx, parent, datetime_save=datetime.datetime.now(), ticked=False):初始化日期时间控件。

    • idx:索引。
    • parent:父组件。
    • datetime_save:初始日期时间,默认为当前时间。
    • ticked:初始勾选状态,默认为False。
    • 设置布局,创建并初始化日期时间编辑控件和复选框。
  • datetime_changed(self):日期时间改变事件处理。

    • 更新日期时间,并通知父组件。
  • ticked_changed(self):勾选状态改变事件处理。

    • 更新勾选状态,并通知父组件。

主函数

代码通过创建 QApplication 实例和 AutoSaveEditor 窗口来执行,并启动应用程序的主循环。

if __name__ == '__main__':
    import sys

    props = Properties('Tests/AutoSaveEditor')
    pp = AutoSaveEditor(props, max_items=20)
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QApplication.instance().exec_()

代码执行

该代码通过命令行执行,创建一个AutoSaveEditor对象,并显示自动保存编辑器窗口。

类的详细说明

AutoSaveEditor

AutoSaveEditor类用于管理和设置定期自动保存的时间。它提供了一个图形用户界面,允许用户添加、编辑和删除自动保存的时间点。

方法:

  • __init__(self, props, max_items, name='regular_auto_save_times', parent=None)

    • 初始化方法,设置布局并加载和初始化日期时间控件。
  • load_AutoSaveEditor_props(props, prop_name, max_items)

    • 静态方法,用于从属性对象中加载日期时间和勾选状态,并返回它们。
  • update_props(props, prop_name, datetimes, ticked)

    • 静态方法,用于更新属性对象中的日期时间和勾选状态。
  • update_datetime(self, idx, datetime_save)

    • 更新指定索引的日期时间。
  • update_ticked(self, idx, ticked)

    • 更新指定索引的勾选状态。
  • accept(self)

    • 接受并保存更改,更新属性并通知父组件,然后关闭窗口。

DateTimeWidget

DateTimeWidget类用于显示和编辑单个日期时间和勾选状态。

方法:

  • __init__(self, idx, parent, datetime_save=datetime.datetime.now(), ticked=False)

    • 初始化方法,设置布局,创建并初始化日期时间编辑控件和复选框。
  • datetime_changed(self)

    • 日期时间改变事件处理,更新日期时间并通知父组件。
  • ticked_changed(self)

    • 勾选状态改变事件处理,更新勾选状态并通知父组件。

9 - 实验时间线查看器

该代码实现了一个实验时间线查看器,通过图形用户界面(GUI)来显示和控制实验时间序列。使用Qt库来构建界面,其中包含按钮、文本框和绘图区域。代码主要包括三个类:TimelineTimelinePlotterSelectorWidget

类和方法

Timeline

Timeline 继承自 QMainWindow,实现了一个实验时间线查看器。

方法:

  • __init__(self, *args, **kwargs):初始化时间线查看器。

    • 设置窗口标题为"Timeline Viewer"。
    • 加载JSON文件中的实验序列。
    • 创建主窗口组件,包括文件加载区、绘图区和选择区。
    • 设置中央窗口部件。
  • plot_experimental_sequence(self, time_dict, init_vals=None):绘制实验时间序列。

    • 重置绘图区域。
    • 深拷贝时间序列字典。
    • 找到最大时间tmax
    • 为每个时间序列添加一个点,确保每个序列都在tmax结束。
    • 准备颜色。
    • 为每个选中的输出绘制折线图,并根据条件选择不同的颜色和填充方式。
  • load_file(self, filename):加载实验序列文件。

    • 读取JSON文件并解析实验序列。
    • 获取输出名称集合。
    • 构建时间序列字典。
    • 逆向设备数据库转换时间序列字典。
    • 更新选择器组件中的名称。
  • decode_ttl_bitmask(self, bitmask, command):解码TTL位掩码。

    • 将位掩码转换为二进制字符串。
    • 找到二进制字符串中的所有1的位置。
    • 根据命令生成TTL字典。
  • get_set_of_used_outputs(self, sequence):获取使用的输出集合。

    • 遍历实验序列,提取所有使用的输出名称。
  • construct_time_sequences(self, sequence, set_of_output_names):构建时间序列字典。

    • 创建时间序列字典结构。
    • 填充时间序列字典。
  • reverse_device_db_transformation(self, time_sequence_dict, device_db_path=workpath+'/configuration/'):逆向设备数据库转换时间序列字典。

    • 加载设备数据库。
    • 构建逆向映射字典。
    • 根据逆向映射字典转换时间序列字典中的名称和值。

TimelinePlotter

TimelinePlotter 继承自 GraphicsLayoutWidget,用于可视化实验序列。

方法:

  • __init__(self, sequence):初始化绘图组件。
    • 订阅属性。
    • 设置背景为白色。
    • 初始化绘图字典。

SelectorWidget

SelectorWidget 继承自 QFrame,用于选择要显示的实验序列。

方法:

  • __init__(self, parent=None, clear_name_dict=None):初始化选择器组件。

    • 创建主布局和按钮。
    • 创建滚动区域用于显示复选框。
  • get_names(self, clear_name_dict):获取并显示名称。

    • 获取清晰名称字典的键并排序。
    • 如果名称未变化,则直接返回。
    • 否则,更新滚动区域中的复选框。
  • select_all(self):全选复选框。

    • 将所有复选框设为选中状态。
  • deselect_all(self):取消全选复选框。

    • 将所有复选框设为未选中状态。

主函数

代码通过创建 QApplication 实例和 Timeline 窗口来执行,并启动应用程序的主循环。

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Timeline()
    window.setWindowIcon(QtGui.QIcon(workpath + '/quatm/icons/time_line.png'))
    window.setWindowTitle('Timeline Viewer')
    window.show()
    sys.exit(app.exec())

代码执行

该代码通过命令行执行,创建一个Timeline对象,并显示实验时间线查看器窗口。

10 - 多线程处理框架

该代码实现了一个基于 Qt 的多线程处理框架。主要包含两个类:WorkerSignals 和 Worker。WorkerSignals 类定义了线程工作时使用的各种信号,而 Worker 类继承自 QRunnable,用于处理多线程任务的设置、执行和信号传递。

功能介绍

该代码实现了一个基于 Qt 的多线程处理框架。主要包含两个类:WorkerSignalsWorkerWorkerSignals 类定义了线程工作时使用的各种信号,而 Worker 类继承自 QRunnable,用于处理多线程任务的设置、执行和信号传递。

代码结构

  • 导入必要的模块和库
  • 定义类 WorkerSignals
  • 定义类 Worker

类:WorkerSignals

简短功能介绍

WorkerSignals 类定义了可从正在运行的工作线程发出的信号。这些信号用于指示线程的各种状态和进度,包括完成、错误、结果和进度更新。

属性

  • finished:无数据的信号,指示线程已完成。
  • error:包含异常类型、值和追溯信息的元组信号。
  • result:处理结果数据的信号。
  • progress:指示进度的整数信号。
  • terminate:终止信号。
  • start:启动信号。
  • publish:发布信号。
  • runDone:运行完成信号。
  • logging:日志信号,包含日志信息字符串。
  • clear:清除信号。

类:Worker

简短功能介绍

Worker 类继承自 QRunnable,用于处理工作线程的设置、信号和结束。它允许在独立线程中运行指定的函数,并通过信号机制与主线程通信。

方法:__init__

功能:初始化 Worker 对象,存储传递的函数及其参数,并设置信号。

参数

  • fn:要在工作线程中运行的函数。
  • args:传递给函数的参数。
  • kwargs:传递给函数的关键字参数。

主要步骤

  1. 调用父类 QRunnable 的构造函数。
  2. 存储传递的函数及其参数。
  3. 初始化 WorkerSignals 对象。
  4. 将进度回调添加到关键字参数中。

方法:run

功能:初始化传递的函数并执行它,处理可能的异常,并通过信号机制传递结果。

主要步骤

  1. 尝试运行传递的函数,并捕获其结果。
  2. 如果发生异常,捕获异常信息并发出 error 信号。
  3. 如果函数运行成功,发出 result 信号传递结果。
  4. 最后,无论是否发生异常,发出 finished 信号指示完成。

11 - 实验任务循环管理器

该代码定义了几个自定义的GUI控件类,包括基础窗口小部件、框架、主窗口以及带有自动完成功能的组合框和自定义的文本编辑控件。这些控件通过继承Qt的基本控件类,并添加了一些自定义的功能来实现。

代码结构

  1. 导入必要的模块和库
  2. 定义主要的 Looper
  3. 定义 LoopItem 类及其子类(TaskItem, ListItem, ConditionalItem 等)
  4. 定义辅助类(DataManager, LoopManager, LoopGroup 等)
  5. 实现 GUI 部件和功能

类:Looper

简短功能介绍

Looper 类是整个循环控制的核心。它负责管理任务组、定时器、按钮和循环的启动与终止。

方法

  • __init__:初始化 Looper 对象,设置属性和布局,创建按钮和标签页。
  • add_tab:添加新的任务组标签页。
  • delete_tab:删除指定的任务组标签页。
  • create_buttons:创建控制按钮。
  • save_loop:保存当前循环配置。
  • load_loop:加载之前保存的循环配置。
  • terminate_by_time:根据时间自动终止循环。

类:LoopItem

简短功能介绍

LoopItem 类是所有循环项的基类,提供了基本的属性和方法。它被 TaskItem, ListItem, ConditionalItem 等类继承,并扩展其功能。

子类:TaskItem

  • 功能:表示单个任务项,执行特定的任务并跟踪运行次数。
  • 方法
    • __init__:初始化任务项,设置任务信息和UI组件。
    • run:执行任务,并将任务添加到任务队列。
    • end_run:更新任务状态和运行次数。
    • task_start:任务开始时的操作。
    • task_end:任务结束时的操作。
    • update_task:更新任务信息。
    • max_check:检查是否达到最大运行次数。

子类:ListItem

  • 功能:表示一个任务列表,按顺序执行列表中的任务。
  • 方法
    • __init__:初始化任务列表项,设置任务列表信息和UI组件。
    • run:执行当前任务,并更新任务索引。
    • end_run:更新任务列表状态和运行次数。
    • edit_list:编辑任务列表。
    • update_task_labels:更新任务标签。

子类:ConditionalItem

  • 功能:表示条件项,根据条件的结果执行不同的任务。
  • 方法
    • __init__:初始化条件项,设置条件信息和UI组件。
    • run:评估条件并选择下一步操作。
    • update_boxes:更新条件的UI组件。

类:DataManager

简短功能介绍

DataManager 类管理数据订阅和更新,处理数据的接收和存储。

方法

  • __init__:初始化数据管理器,设置属性和数据客户端。
  • set_new_data:处理新的数据,更新数据字典。
  • edit_subscriptions:编辑数据订阅。

类:LoopManager

简短功能介绍

LoopManager 类负责管理循环的执行,处理循环任务的启动、终止和控制。

方法

  • __init__:初始化循环管理器,设置属性和线程池。
  • loop_fn:循环执行函数,处理循环任务。
  • run_loop:启动循环任务。
  • terminate:终止循环任务。
  • task_start:任务开始时的操作。
  • task_end:任务结束时的操作。

类:LoopGroup

简短功能介绍

LoopGroup 类表示一个任务组,包含多个任务项和一个组项。

方法

  • __init__:初始化任务组,设置属性和布局。
  • create_buttons:创建任务组的控制按钮。
  • delete_group:删除任务组。
  • update_loop_group_file:更新任务组配置文件。

类:Baustelle

简短功能介绍

Baustelle 类是任务组的编辑器,提供添加、删除和编辑任务项的功能。

方法

  • __init__:初始化编辑器,设置属性和布局。
  • add_task_item:添加新的任务项。
  • add_list_item:添加新的任务列表项。
  • add_conditional:添加新的条件项。
  • add_group_item:添加新的组项。
  • update_idx:更新任务项的索引。

类:LoopSubMgr

简短功能介绍

LoopSubMgr 类是一个GUI,用于编辑数据流的订阅。

方法

  • __init__:初始化订阅管理器,设置属性和布局。
  • update_subscriptions:更新数据流的订阅。

类:ListEdit

简短功能介绍

ListEdit 类是一个对话框,用于编辑 ListItem 的任务列表。

方法

  • __init__:初始化对话框,设置属性和布局。
  • closeEvent:在对话框关闭时更新任务列表。

类:PrepBox 和 ListBox

简短功能介绍

PrepBoxListBox 类分别用于显示和管理预备任务列表和当前任务列表。

方法

  • init_ui:初始化UI组件。
  • set_model:设置数据模型。
  • push_selection:将选中的任务添加到任务列表。
  • unpack_selection:解包选中的任务并添加到任务列表。
  • move_up:在任务列表中上移任务。
  • move_down:在任务列表中下移任务。
  • delete_clicked:删除选中的任务。

类:VLine

简短功能介绍

VLine 类用于在UI中创建分隔线。

类:LoopTabWidget 和 EditableTabBar

简短功能介绍

LoopTabWidgetEditableTabBar 类自定义了标签页控件,允许编辑标签页名称和管理标签页。

方法

  • addTab:添加新的标签页。
  • setIconOn:设置标签页的图标为启用状态。
  • setIconOff:设置标签页的图标为禁用状态。
  • setTabText:设置标签页的文本。
  • editTab:编辑标签页名称。

辅助函数

功能

  • get_experiment:获取实验对象。
  • edit_key_in_place:编辑字典中的键。
  • find_or_add:在组合框中查找或添加项目。
  • parse_text:解析文本,转换为特定格式。

12 - 实验任务预备队列管理器

该代码定义了几个自定义的GUI控件类,包括基础窗口小部件、框架、主窗口以及带有自动完成功能的组合框和自定义的文本编辑控件。这些控件通过继承Qt的基本控件类,并添加了一些自定义的功能来实现。

概要

该代码定义了用于管理和展示队列(Queue)和准备站(PrepStation)表格的模型。模型指定了表格数据的形式(如字典或列表),以及如何展示和操作这些数据,包括如何获取、设置和删除数据,以及如何排序数据。模型可以直接从数据集中读取数据,并在数据集发生更改时自动更新表格。

主要类和功能

_SyncSubstruct

此类定义了用于操作表格数据字典的方法。方法包括添加、插入、弹出、设置、删除和获取字典项。这个类主要是为了便于在模型中更新数据字典,并在数据更新时调用回调函数来通知模型。

DictSyncModel

这是一个基类,用于将字典(backing_store)转换为表格。模型可以读取和编辑字典中的数据,并根据需要更新表格显示。其主要功能包括:

  • 初始化模型,设置表头、数据名称和初始数据。
  • 获取行数和列数。
  • 获取和设置单元格数据。
  • 获取表头数据。
  • 插入和删除字典项。
  • 排序和转换数据。
关键方法
  • rowCount: 返回字典中的条目数。
  • columnCount: 返回列的数量,即表头的数量。
  • data: 根据索引和角色获取数据。
  • setData: 设置单元格数据,并根据需要进行类型转换。
  • headerData: 获取表头数据。
  • __setitem__: 插入或更新字典项,并更新表格显示。
  • __delitem__: 删除字典项,并更新表格显示。
  • __getitem__: 获取字典项。
  • sort_key: 定义排序键(由子类实现)。
  • convert: 将字典键转换为列数据(由子类实现)。
  • flags: 定义单元格的属性(由子类实现)。

ScheduleModel

这是用于管理实验队列的表格模型。数据结构是一个字典,每个字典代表一个实验任务。任务按优先级和任务编号排序。

关键方法
  • sort_key: 返回用于排序的键,首先按优先级排序,然后按任务编号排序。
  • convert: 将字典键转换为列数据,特别是将日期时间字符串转换为 QDateTime 对象。
  • flags: 定义可编辑和不可编辑的列。

ListSyncModel

类似于 DictSyncModel,但处理的是列表而不是字典。主要用于管理需要按顺序排列的数据集合。

关键方法
  • rowCount: 返回列表的长度。
  • columnCount: 返回列的数量。
  • data: 根据索引和角色获取数据。
  • setData: 设置单元格数据,并根据需要进行类型转换。
  • headerData: 获取表头数据。
  • __delitem__: 删除列表项,并更新表格显示。
  • __getitem__: 获取列表项。
  • sort_key: 定义排序键(由子类实现)。
  • convert: 将列表项转换为列数据(由子类实现)。
  • flags: 定义单元格的属性(由子类实现)。

PrepModel

这是用于准备站的表格模型,使用列表来管理任务,因为准备站中的任务不需要唯一的 ID,可以自由更改顺序。

关键方法
  • convert: 将列表项转换为列数据,特别是将日期时间字符串转换为 QDateTime 对象。
  • flags: 定义可编辑和不可编辑的列。

功能特点

  • 数据同步:模型可以同步更新数据字典或列表,并通知表格更新显示。
  • 数据排序:模型可以根据指定的键对数据进行排序。
  • 数据转换:模型可以根据列索引转换数据类型,如将日期时间字符串转换为 QDateTime 对象。
  • 数据编辑:模型支持在表格中编辑数据,并将更改反映到原始数据集合中。
  • 表格属性:模型可以定义哪些列是可编辑的,哪些是只读的。

运行流程

  1. 创建模型实例,传入初始数据。
  2. 模型通过 rowCountcolumnCount 方法告知表格数据的大小。
  3. 表格通过 data 方法获取单元格数据并显示。
  4. 当用户编辑表格时,模型通过 setData 方法更新数据集合。
  5. 模型通过发射信号通知表格数据已更改,表格自动更新显示。

13 - 实验运行调度管理器

Prepper 类是 Quatm 实验调度与运行系统的核心组件,负责管理实验队列、线程调度和状态跟踪。

概述

Prepper 类(位于 quatm.gui.prepper 模块)是实验调度和运行系统的核心,提供以下核心能力:

  • 任务队列管理:维护待执行的实验任务列表
  • 线程调度:基于线程池的单线程调度策略,避免并发冲突
  • 状态跟踪:通过 expDict 追踪每个实验的配置和运行状态
  • 定时轮询:周期性检查任务状态并更新 UI

核心架构

graph TD
    A[实验任务入队] --> B[queue 任务队列]
    B --> C[threadpool 线程池]
    C --> D[执行实验]
    D --> E[expDict 状态更新]
    E --> F[timer 定时刷新 UI]
    F --> G[browser 界面展示]

API 参考

构造函数

from quatm.gui.prepper import Prepper

prepper = Prepper(browser=None)
参数类型必填说明
browserobject浏览器/UI 对象,用于界面交互和状态展示

成员变量

变量类型说明
browserobject关联的 UI 浏览器对象
queueQueue实验任务队列(FIFO)
expDictdict实验配置与状态字典
threadpoolThreadPoolExecutor线程池(max_workers=1)
timerQTimerUI 定时刷新器

使用示例

基础用法

from quatm.gui.prepper import Prepper
from quatm.experiments import RabiExperiment

# 1. 初始化调度器
prepper = Prepper(browser=my_browser)

# 2. 创建实验并加入队列
exp = RabiExperiment(
    qubit="q0",
    durations=[10, 20, 50, 100],  # ns
    amplitudes=[0.1, 0.2, 0.3, 0.4]
)
prepper.queue.put(exp)

# 3. 启动调度(从队列中取出并执行)
prepper.start()

批量实验调度

# 批量提交多个实验
experiments = [
    RabiExperiment(qubit="q0", durations=range(10, 100, 10)),
    RamseyExperiment(qubit="q0", delays=range(0, 1000, 50)),
    T1Experiment(qubit="q0", wait_times=range(1, 100, 5)),
]

for exp in experiments:
    prepper.queue.put(exp)

# 调度器会按 FIFO 顺序逐个执行
prepper.start()

线程模型

Prepper 使用 max_workers=1 的线程池设计,原因如下:

  1. 硬件安全:避免多个实验同时操作同一 FPGA 控制器,防止寄存器冲突
  2. 状态一致性:确保 expDict 在单线程下读写安全,无需加锁
  3. 可预测性:实验按入队顺序严格串行执行,结果可复现
from concurrent.futures import ThreadPoolExecutor

# Prepper 内部等价于:
self.threadpool = ThreadPoolExecutor(max_workers=1)

错误处理

调度器内置了异常捕获机制,通过 traceback 模块记录详细的堆栈信息:

import traceback

def _run_experiment(self, exp):
    try:
        result = exp.run()
        self.expDict[exp.id] = {"status": "done", "result": result}
    except Exception as e:
        self.expDict[exp.id] = {
            "status": "error",
            "error": str(e),
            "traceback": traceback.format_exc()
        }

实验失败不会中断调度器——错误被记录在 expDict 中,后续任务继续执行。

扩展指南

添加调度策略

如需支持优先级调度或依赖调度,可以扩展 Prepper 类:

class PriorityPrepper(Prepper):
    """支持优先级调度的实验管理器"""

    def __init__(self, browser=None):
        super().__init__(browser)
        from queue import PriorityQueue
        self.queue = PriorityQueue()

    def submit(self, exp, priority=0):
        """提交实验并指定优先级(数值越小优先级越高)"""
        self.queue.put((priority, exp))

添加实验类型

通过实现统一的实验接口,Prepper 可以支持任意实验类型:

class BaseExperiment:
    """所有实验的基类"""

    def run(self):
        raise NotImplementedError

    @property
    def id(self):
        return id(self)

# Prepper 通过鸭子类型支持任何实现了 run() 方法的对象

常见问题

Q: 为什么线程池大小固定为 1? A: 量子物理实验中,多个实验同时操作同一硬件可能导致不可预料的结果。单线程模型保证了时序确定性。

Q: 如何查看当前队列中的任务? A: 通过 prepper.queue.qsize() 获取待执行任务数,通过 prepper.expDict 查看各实验状态。

Q: 实验执行中可以暂停吗? A: 任何进程或者子进程都可以在实验执行过程中随时暂停、编辑、删除和添加。

14 - 实验预处理

该代码展示了一个名为 PrepStation 的类,用于实验的预处理和队列管理。

详细代码分析:PrepStation 类及其相关组件

该代码展示了一个名为 PrepStation 的类,用于实验的预处理和队列管理。以下是对代码的详细分析,涵盖导入的模块、类的定义及其成员、注释和错误处理等方面。

PrepStation 类

PrepStation 类是该代码的核心部分,用于管理实验任务的预处理和队列操作。以下是对该类的详细分析:

初始化方法
  • __init__ 方法
    • 初始化类实例,并设置初始状态或配置。
    • 接受 browserparenttitle 作为参数。
    • 初始化各类成员变量,如 parentbrowserqueueexpDictqWidgetlayoutbuttonLayoutprops_taskparamDirtableprepList
    • 调用 init_uiinit_table_actions 方法来设置界面和表格操作。
初始化界面
  • init_ui 方法
    • 配置表格的垂直头,使其根据内容调整大小并隐藏。
    • 创建各种按钮并设置其图标、工具提示和点击事件。
    • 将按钮添加到布局中,并设置布局对齐方式。
初始化表格操作
  • init_table_actions 方法
    • 创建各种操作(如删除、休眠、推送、循环、编辑、查看和保存)并设置其快捷键和触发事件。
    • 将这些操作添加到表格中。
设置模型
  • set_model 方法
    • 创建 PrepModel 实例并设置为表格模型。
    • 调整表格列的宽度。
加载之前的任务
  • load_previous 方法
    • prepfile.json 文件中加载之前的任务列表,并打开相关的实验窗口。
    • 更新 prepList
任务操作方法
  • push 方法

    • 将选中的任务推送到队列中,如果没有选中任务,则推送第一个任务。
  • push_row 方法

    • 推送指定行的任务到队列中,并更新任务状态。
  • push_first 方法

    • 推送第一个任务到队列中。
  • delete_clicked 方法

    • 删除选中的任务,并更新任务文件。
  • set_sleeping 方法

    • 设置选中的任务为休眠状态。
  • push_to_looper 方法

    • 将选中的任务推送到循环器中。
  • move_up 方法

    • 上移选中的任务。
  • move_down 方法

    • 下移选中的任务。
  • update_prep_file 方法

    • 更新任务文件,将当前任务列表保存到 prepfile.json
编辑和查看参数
  • open_editor 方法

    • 打开任务编辑器窗口以修改任务参数。
  • open_viewer 方法

    • 打开参数查看器窗口以查看任务参数。
  • save_params 方法

    • 将实验参数保存到 JSON 文件中。

其他类和辅助函数

  • ExpEditWindow

    • 用于编辑实验参数的窗口。
    • 初始化方法 __init__init_ui
    • 提交修改的方法 submit
  • ParViewWindow

    • 用于查看实验参数的窗口。
    • 初始化方法 __init__init_ui
  • CheckLayout

    • 包含复选框和参数输入框的布局。
    • 初始化方法 __init__
  • DisplayBox

    • 显示参数名称、值和单位的布局。
    • 初始化方法 __init__init_ui
  • get_experiment 函数

    • 获取实验实例,如果实验窗口未打开则打开窗口。

15 - 实验集合管理器

该代码定义了一个用于管理和监控多个进程的图形用户界面(GUI)应用程序。

环境变量设置

代码通过检查操作系统平台设置了 QT_SCALE_FACTOR 环境变量,以调整 MacOS 上的缩放比例。

SingleProcess 类

SingleProcess 类用于表示单个可管理的进程。以下是该类的详细分析:

初始化方法
  • __init__ 方法
    • 初始化类实例,并设置初始状态或配置。
    • 接受 scriptnameactivecategoryparent 作为参数。
    • 根据操作系统平台设置 Python 解释器路径。
    • 创建和配置按钮、布局和样式表。
    • 配置定时器以定期更新进程状态。
进程管理方法
  • startProcess 方法

    • 停止现有进程(如果有)。
    • 使用 subprocess.Popen 启动新的进程。
    • 更新按钮状态。
  • stopProcess 方法

    • 停止现有进程,根据需要选择终止或强制杀死进程。
    • 更新按钮状态。
  • updateStatus 方法

    • 定期检查进程状态并更新按钮颜色以指示进程是否运行。
析构方法
  • __del__ 方法
    • 确保在对象销毁时停止进程。

ProcessManager 类

ProcessManager 类用于管理多个 SingleProcess 实例。以下是该类的详细分析:

初始化方法
  • __init__ 方法
    • 初始化类实例,并设置初始状态或配置。
    • 读取配置文件,创建 SingleProcess 实例,并将其添加到布局中。
    • 设置窗口样式和布局。
事件处理方法
  • closeEvent 方法
    • 在关闭窗口时,停止所有正在运行的进程。
析构方法
  • __del__ 方法
    • 在对象销毁时输出调试信息。

主函数

  • main 方法
    • 设置高 DPI 缩放策略。
    • 创建应用程序实例,设置窗口图标,创建和显示主窗口。
    • 进入应用程序事件循环。

结论

该代码实现了一个进程管理和监控的 GUI 应用程序。通过 SingleProcess 类,用户可以启动、停止和监控单个进程;通过 ProcessManager 类,用户可以批量管理多个进程。代码结构清晰,使用了 Qt 的多种控件和信号槽机制来实现用户交互和数据更新。

16 - 实验参数管理器

该代码定义了一个用于管理和监控多个进程的图形用户界面(GUI)应用程序。

DefaultExp 类概述

DefaultExp 是一个实验类,包含所有设备的属性,并组织这些属性以便于管理和访问。

方法详解

build(self)
  • 功能
    • 设置实验的初始参数,如计数器。
    • 遍历设备数据库,加载设备并根据设备类型进行分组。
    • 处理属性的加载错误,并将设备分为显示和隐藏两类。
run(self)
  • 功能
    • 运行实验的主要逻辑(此处为空实现,作为模板)。

BasicManager 类概述

BasicManager 是一个基础管理类,用于创建和管理各种类型的参数小部件。

构造方法

  • 参数说明

    • props:属性对象,用于与属性数据库交互。
    • parent:父级小部件。
    • kwargs:其他参数,用于初始化属性。
  • 功能

    • 初始化基础属性,如单位、最大最小值、步长等。
    • 设置样式并调用 _initGUI 方法。

方法详解

_initGUI(self)
  • 功能
    • 初始化图形界面,创建布局和标签。
    • 如果存在工具提示,则设置工具提示。
    • 创建定时器,用于定期更新参数值。
updateSpin(self)
  • 功能
    • 占位方法,用于在子类中实现具体的更新逻辑。

IntManager 类概述

IntManager 继承自 BasicManager,用于管理整数类型的参数。

方法详解

initSpin(self)
  • 功能
    • 创建一个整数选择框 (QSpinBox)。
    • 从属性对象中获取初始值并设置到选择框中。
    • 连接选择框的值变化信号到 updateValue 方法。
updateValue(self, v)
  • 参数

    • v:新值。
  • 功能

    • 更新实验和属性对象中的参数值。
updateSpin(self)
  • 功能
    • 检查属性对象中的值是否有变化,如果有变化,则更新选择框中的值。

BoolManager 类概述

BoolManager 继承自 QCheckBox,用于管理布尔类型的参数。

方法详解

updateValue(self, val)
  • 参数

    • val:新值。
  • 功能

    • 更新实验和属性对象中的布尔值。
updateCheckbox(self)
  • 功能
    • 检查属性对象中的布尔值是否有变化,如果有变化,则更新复选框的状态。

FloatManager 类概述

FloatManager 继承自 IntManager,用于管理浮点数类型的参数。

方法详解

initSpin(self)
  • 功能
    • 创建一个浮点数选择框 (QDoubleSpinBox)。
    • 从属性对象中获取初始值并设置到选择框中。
    • 连接选择框的值变化信号到 updateValue 方法。

ComboManager 类概述

ComboManager 继承自 BasicManager,用于管理下拉列表类型的参数。

方法详解

initSpin(self)
  • 功能
    • 创建一个下拉列表 (QComboBox)。
    • 根据提供的字符串列表初始化下拉列表的选项。
    • 连接下拉列表的选项变化信号到 updateValue 方法。
updateValue(self, v)
  • 参数

    • v:新值。
  • 功能

    • 更新实验和属性对象中的选项值。

FrequencyManager 类概述

FrequencyManager 继承自 IntManager,用于管理频率类型的参数。

方法详解

initSpin(self)
  • 功能
    • 创建一个浮点数选择框 (QDoubleSpinBox),用于选择频率值。
    • 从属性对象中获取初始值并设置到选择框中。
    • 连接选择框的值变化信号到 updateValue 方法。

SimpleDefaults 类概述

SimpleDefaults 继承自 QFrame,用于显示和管理实验的默认参数。

构造方法

  • 功能
    • 初始化属性对象和实验对象。
    • 调用实验对象的 build 方法构建实验。
    • 创建和设置主布局。
    • 根据实验的分组创建相应的参数管理小部件,并添加到布局中。

主函数

main()

  • 功能
    • 创建应用程序实例。
    • 创建 SimpleDefaults 窗口并显示。
    • 启动应用程序的事件循环。

使用场景

  • 该代码主要用于科学实验和数据采集系统中,帮助管理和显示实验的各种参数。
  • 适用于需要频繁调整参数和查看参数变化的场景,如实验室研究和工业控制系统。

17 - 实验运行监视器

这个代码定义了一个 StreamMonitor 类和一个 TableModel 类,用于监控和显示各种数据流(包括数据流、图像流、命令流和消息流)的内容。它还提供了一个主函数 main,用于初始化和运行一个包含多个标签页的 PyQt 应用程序,每个标签页显示不同类型的数据流。

概述

这个代码定义了一个 StreamMonitor 类和一个 TableModel 类,用于监控和显示各种数据流(包括数据流、图像流、命令流和消息流)的内容。它还提供了一个主函数 main,用于初始化和运行一个包含多个标签页的 PyQt 应用程序,每个标签页显示不同类型的数据流。

StreamMonitor

StreamMonitor 类继承自 QWidget,用于监控和显示不同类型的数据流。

主要方法和属性

  • 初始化方法 __init__

    • 接受参数:name(数据流名称)、streamtype(数据流类型,如 ‘Data’、‘Image’ 等)、parent(父组件)。
    • 根据 streamtype 初始化不同类型的客户端对象(如 DataClientImageClient 等)。
    • 初始化用户界面,包括标签、复选框、组合框、按钮、文本编辑器和表格视图等。
    • 设置一个定时器,用于定期更新数据流的内容。
  • _update_message 方法

    • 定期从消息流中获取新消息,并将其添加到消息列表中。
    • 如果启用了保存选项,则将新消息写入文件。
  • update_text 方法

    • 根据用户选择的过滤条件更新显示的消息内容。
    • 使用 QTableView 显示过滤后的消息列表。
  • _update_selected_message 方法

    • 从文件中读取历史消息,并更新显示内容。
  • _update_list 方法

    • 定期从数据流中获取新数据,并将其添加到消息列表中。
  • load_selected_message 方法

    • 打开文件对话框,允许用户选择一个消息文件,并加载文件内容。
  • update_table_selected 方法

    • 根据用户选择的过滤条件更新显示的历史消息内容。
  • on_checkbox_changed 方法

    • 处理复选框状态变化事件。

TableModel

TableModel 类继承自 QAbstractTableModel,用于管理和显示表格数据。

主要方法和属性

  • 初始化方法 __init__

    • 接受参数:data(表格数据),并初始化模型。
  • data 方法

    • 根据指定的索引和角色返回相应的数据内容和样式。
  • rowCount 方法

    • 返回表格的行数。
  • columnCount 方法

    • 返回表格的列数。
  • headerData 方法

    • 返回表头的标签内容。

使用场景

  • 该代码主要用于需要监控和显示实时数据流的应用程序。
  • 适用于数据分析、系统监控和日志管理等场景。
  • 提供了一种用户友好的方式,通过图形界面查看和管理不同类型的数据流和消息内容。

主函数 main

  • 创建一个包含多个标签页的 QTabWidget,每个标签页显示不同类型的数据流。
  • 初始化和运行 PyQt 应用程序。

通过这种方式,用户可以方便地在一个界面中监控和管理多种类型的数据流和消息内容。

18 - 实验任务折叠管理

这段代码定义了一个可折叠的对话框组件,允许用户在应用程序中添加和管理可折叠的部分。主要组件包括 SectionExpandButton 类和 CollapsibleDialog 类,它们协同工作以实现可折叠部分的创建和管理。

概述

这段代码定义了一个可折叠的对话框组件,允许用户在应用程序中添加和管理可折叠的部分。主要组件包括 SectionExpandButton 类和 CollapsibleDialog 类,它们协同工作以实现可折叠部分的创建和管理。

主要组件

SectionExpandButton

SectionExpandButton 类继承自 QPushButton,用于创建一个可以展开或折叠其关联部分的按钮。

主要方法和属性
  • 初始化方法 __init__

    • 接受参数:item(关联的部分项)、text(按钮文本)、parent(父组件)。
    • 设置按钮的初始文本,并连接点击事件到 on_clicked 方法。
  • on_clicked 方法

    • 处理按钮的点击事件,切换关联部分的展开或折叠状态。
    • 如果部分是展开的,则将其折叠;如果是折叠的,则将其展开。

CollapsibleDialog

CollapsibleDialog 类继承自 QDialog,用于创建一个包含可折叠部分的对话框。

主要方法和属性
  • 初始化方法 __init__

    • 创建并配置一个 QTreeWidget 以隐藏标题,并将其添加到对话框的布局中。
    • 设置树的缩进为 0。
  • add_section 方法

    • 接受参数:title(部分的标题)、widget(部分的内容部件)。
    • 调用 add_button 方法创建一个按钮,并调用 add_widget 方法将内容部件添加为按钮的子项。
  • define_sections 方法

    • 定义并添加对话框中的所有部分。
    • 示例实现中,创建了一个包含两个标签的 QFrame 部件,并将其添加到部分中。
  • add_button 方法

    • 接受参数:title(部分的标题)。
    • 创建一个 QTreeWidgetItem 项,并将其添加为树的顶级项。
    • 创建一个 SectionExpandButton 按钮,将其设置为项的部件,并返回该项。
  • add_widget 方法

    • 接受参数:button(按钮项)、widget(部分的内容部件)。
    • 创建一个 QTreeWidgetItem 项,将其设置为按钮项的子项,并将内容部件设置为子项的部件。

使用场景

这个组件可以用于需要包含多个可折叠部分的对话框的应用程序,例如设置对话框、信息面板等。通过扩展 CollapsibleDialog 类并重写 define_sections 方法,可以轻松定义和管理对话框中的各个部分。

示例

下面是一个示例,展示如何使用 CollapsibleDialogSectionExpandButton 类:

import sys
from PyQt6.QtWidgets import QApplication

class MyCollapsibleDialog(CollapsibleDialog):
    def define_sections(self):
        widget1 = QFrame(self.tree)
        layout1 = QHBoxLayout(widget1)
        layout1.addWidget(QLabel("Content 1"))
        self.add_section("Section 1", widget1)
        
        widget2 = QFrame(self.tree)
        layout2 = QHBoxLayout(widget2)
        layout2.addWidget(QLabel("Content 2"))
        self.add_section("Section 2", widget2)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    dialog = MyCollapsibleDialog()
    dialog.define_sections()
    dialog.show()
    sys.exit(app.exec())

在这个示例中,MyCollapsibleDialog 类继承自 CollapsibleDialog 并重写了 define_sections 方法,定义了两个可折叠部分。运行此代码将显示一个包含两个可折叠部分的对话框。