Пример #1
0
class BaseFilterView(QLabel):
    def __init__(self, controller, model):
        super().__init__()
        self.controller = controller
        self.model = model
        self._init_UI()

    def _init_UI(self):
        self.setFixedHeight(120)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.layout = QVBoxLayout()
        self.layout.setSpacing(2)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setAlignment(Qt.AlignTop)
        self.setLayout(self.layout)

        self.title = QLabel()
        self.title.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)

        self.list_view = QListWidget()
        self.list_view.setFixedHeight(100)
        self.list_view.setSelectionMode(QAbstractItemView.MultiSelection)
        self.list_view.itemSelectionChanged.connect(self._on_item_selected)

        self.layout.addWidget(self.title)
        self.layout.addWidget(self.list_view)

    def set_title(self, text: str) -> None:
        self.title.setText(text)

    def set_items(self, texts: tuple[str, ...]) -> None:
        self.list_view.clear()
        for text in texts:
            self._add_item(text)

    def _add_item(self, text: str) -> None:
        item = QListWidgetItem(text)
        item.setTextAlignment(Qt.AlignHCenter)
        self.list_view.addItem(item)

    def _on_item_selected(self) -> None:
        selected = [item.text() for item in self.list_view.selectedItems()]
        self.controller.on_item_selected(selected)

    def clear_selection(self) -> None:
        self.list_view.clearSelection()
Пример #2
0
class BWPassengerWindow(QMdiSubWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setBaseSize(400, 400)

        self.centralwidget = QWidget(self)
        self.setWidget(self.centralwidget)

        layout = QHBoxLayout(self.centralwidget)
        self.passengerlist = QListWidget(self.centralwidget)
        layout.addWidget(self.passengerlist)
        self.setWindowTitle("Passengers")

    def reset(self):
        self.passengerlist.clearSelection()
        self.passengerlist.clear()

    def add_passenger(self, passenger_name, passenger_id):
        item = BWEntityEntry(passenger_id,
                             passenger_name)
        self.passengerlist.addItem(item)

    def set_title(self, entityname):
        self.setWindowTitle("Passengers - {0}".format(entityname))
Пример #3
0
class StatModUseful(QScrollArea):
    """
    This class is not called directly by HABBY, but it is the parent class of EstihabW and FstressW. As fstress and
    estimhab have a similar graphical user interface, this architecture allows to re-use some functions between the
    two classes, which saves a bit of coding.
    """
    send_log = pyqtSignal(str, name='send_log')
    """
    PyQtsignal to write the log.
    """
    show_fig = pyqtSignal()
    """
    PyQtsignal to show the figures.
    """
    def __init__(self):
        super().__init__()
        self.path_bio = 'biology'
        self.eq1 = QLineEdit()
        self.ew1 = QLineEdit()
        self.eh1 = QLineEdit()
        self.eq2 = QLineEdit()
        self.ew2 = QLineEdit()
        self.eh2 = QLineEdit()
        self.eqmin = QLineEdit()
        self.eqmax = QLineEdit()
        self.target_lineedit_list = []
        self.add_qtarget_button = QPushButton()
        self.add_qtarget_button.setIcon(
            QIcon(os.path.join(os.getcwd(), "file_dep", "icon", "plus.png")))
        self.add_qtarget_button.setStyleSheet(
            "background-color: rgba(255, 255, 255, 0);")
        self.add_qtarget_button.setToolTip(
            self.tr("Click to add one target discharge."))
        # self.add_qtarget_button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.remove_qtarget_button = QPushButton()
        self.remove_qtarget_button.setIcon(
            QIcon(os.path.join(os.getcwd(), "file_dep", "icon", "moins.png")))
        self.remove_qtarget_button.setStyleSheet(
            "background-color: rgba(255, 255, 255, 0);")
        self.remove_qtarget_button.setToolTip(
            self.tr("Click to remove one target discharge."))
        self.list_f = QListWidget()
        self.selected_aquatic_animal_qtablewidget = QListWidget()

        self.msge = QMessageBox()
        self.fish_selected = []
        self.qall = [
        ]  # q1 q2 qmin qmax q50. Value cannot be added directly because of stathab.

    def add_fish(self):
        """
        The function is used to select a new fish species (or inverterbrate)
        """
        items = self.list_f.selectedItems()
        ind = []
        if items:
            for i in range(0, len(items)):
                # avoid to have the same fish multiple times
                if items[i].text() in self.fish_selected:
                    pass
                else:
                    self.fish_selected.append(items[i].text())

        # order the list (careful QLIstWidget do not order as sort from list)
        if self.fish_selected:
            self.fish_selected.sort()
            self.selected_aquatic_animal_qtablewidget.clear()
            self.selected_aquatic_animal_qtablewidget.addItems(
                self.fish_selected)
            # bold for selected fish
            font = QFont()
            font.setBold(True)
            for i in range(0, self.list_f.count()):
                for f in self.fish_selected:
                    if f == self.list_f.item(i).text():
                        self.list_f.item(i).setFont(font)

    def remove_fish(self):
        """
        The function is used to remove fish species (or inverterbates species)
        """
        item = self.selected_aquatic_animal_qtablewidget.takeItem(
            self.selected_aquatic_animal_qtablewidget.currentRow())
        try:
            self.fish_selected.remove(item.text())
        except ValueError:
            pass
        # bold for selected fish
        font = QFont()
        font.setBold(False)
        for i in range(0, self.list_f.count()):
            if item.text() == self.list_f.item(i).text():
                self.list_f.item(i).setFont(font)
        item = None

    def remove_all_fish(self):
        """
        This function removes all fishes from the selected fish
        """
        self.selected_aquatic_animal_qtablewidget.clear()
        self.list_f.clear()
        self.fish_selected = []
        self.list_f.addItems(self.data_fish[:, 0])

    def add_sel_fish(self):
        """
        This function loads the xml file and check if some fish were selected before. If yes, we add them to the list
        """

        # open the xml file
        filename_path_pro = os.path.join(self.path_prj,
                                         self.name_prj + '.habby')
        if os.path.isfile(filename_path_pro):
            parser = ET.XMLParser(remove_blank_text=True)
            doc = ET.parse(filename_path_pro, parser)
            root = doc.getroot()
            # get the selected fish
            child = root.find(".//Habitat/fish_selected")
            if child is not None:
                fish_selected_b = child.text
                if fish_selected_b is not None:
                    if ',' in fish_selected_b:
                        fish_selected_b = fish_selected_b.split(',')
                    # show it
                    for i in range(0, self.list_f.count()):
                        self.list_f.clearSelection()
                        self.list_f.setCurrentRow(i)
                        items = self.list_f.selectedItems()
                        if items:
                            fish_l = items[0].text()
                            if fish_l in fish_selected_b:  # do not work with space here
                                self.add_fish()

    def find_path_im_est(self):
        """
        A function to find the path where to save the figues. Careful there is similar function in sub_and_merge_GUI.py.
        Do not mix it up

        :return: path_im a string which indicates the path to the folder where are save the images.
        """
        # to insure the existence of a path
        path_im = 'no_path'

        filename_path_pro = os.path.join(self.path_prj,
                                         self.name_prj + '.habby')
        if os.path.isfile(filename_path_pro):
            parser = ET.XMLParser(remove_blank_text=True)
            doc = ET.parse(filename_path_pro, parser)
            root = doc.getroot()
            child = root.find(".//path_figure")
            if child is None:
                path_test = os.path.join(self.path_prj, r'/figures')
                if os.path.isdir(path_test):
                    path_im = path_test
                else:
                    path_im = self.path_prj
            else:
                path_im = os.path.join(self.path_prj, child.text)
        else:
            self.send_log.emit(
                QCoreApplication.translate("StatModUseful", 'Warning: ') +
                QCoreApplication.translate(
                    "StatModUseful",
                    "The project is not saved. Save the project in the General tab."
                ))

        return path_im

    def find_path_hdf5_est(self):
        """
        A function to find the path where to save the hdf5 file. Careful a simialar one is in sub_and_merge_GUI.py and in
        stathab_c. By default, path_hdf5 is in the project folder in the folder 'hdf5'.
        """

        path_hdf5 = 'no_path'

        filename_path_pro = os.path.join(self.path_prj,
                                         self.name_prj + '.habby')
        if os.path.isfile(filename_path_pro):
            path_hdf5 = load_project_properties(self.path_prj)["path_hdf5"]
            # parser = ET.XMLParser(remove_blank_text=True)
            # doc = ET.parse(filename_path_pro, parser)
            # root = doc.getroot()
            # child = root.find(".//path_hdf5")
            # if child is None:
            #     path_hdf5 = os.path.join(self.path_prj, 'hdf5')
            # else:
            #     path_hdf5 = os.path.join(self.path_prj, child.text)
        else:
            self.send_log.emit(
                QCoreApplication.translate("StatModUseful", 'Warning: ') +
                QCoreApplication.translate(
                    "StatModUseful",
                    "The project is not saved. Save the project in the General tab."
                ))

        return path_hdf5

    def find_path_text_est(self):
        """
        A function to find the path where to save the hdf5 file. Careful a simialar one is in estimhab_GUI.py. By default,
        path_hdf5 is in the project folder in the folder 'hdf5'.
        """

        # filename_path_pro = os.path.join(self.path_prj, self.name_prj + '.habby')
        # if os.path.isfile(filename_path_pro):
        #     parser = ET.XMLParser(remove_blank_text=True)
        #     doc = ET.parse(filename_path_pro, parser)
        #     root = doc.getroot()
        #     child = root.find(".//path_text")
        #     if child is None:
        #         path_text = os.path.join(self.path_prj, r'/output/text')
        #     else:
        #         path_text = os.path.join(self.path_prj, child.text)
        # else:
        #     self.send_log.emit('Warning: ' + QCoreApplication.translate("StatModUseful", "The project is not saved. Save the project in the General tab."))

        return os.path.join(self.path_prj, "output", "text")

    def find_path_output_est(self, att):
        """
        A function to find the path where to save the shapefile, paraview files and other future format. Here, we gave
        the xml attribute as argument so this functin can be used to find all path needed. However, it is less practical
        to use as the function above as one should remember the xml tribute to call this function. However, it can be
        practical to use to add new folder. Careful a similar function is in Hydro_GUI_2.py.

        :param att: the xml attribute (from the xml project file) linked to the path needed, without the .//

        """

        path_out = 'no_path'

        filename_path_pro = os.path.join(self.path_prj,
                                         self.name_prj + '.habby')
        if os.path.isfile(filename_path_pro):
            parser = ET.XMLParser(remove_blank_text=True)
            doc = ET.parse(filename_path_pro, parser)
            root = doc.getroot()
            child = root.find(".//" + att)
            if child is None:
                return self.path_prj
            else:
                path_out = os.path.join(self.path_prj, child.text)
        else:
            self.send_log.emit(
                QCoreApplication.translate("StatModUseful", 'Warning: ') +
                QCoreApplication.translate(
                    "StatModUseful",
                    "The project is not saved. Save the project in the General tab."
                ))

        return path_out

    def find_path_input_est(self):
        """
        A function to find the path where to save the input file. Careful a similar one is in sub_and_merge_GUI.py. By default,
        path_input indicates the folder 'input' in the project folder.
        """

        # path_input = 'no_path'
        #
        # filename_path_pro = os.path.join(self.path_prj, self.name_prj + '.habby')
        # if os.path.isfile(filename_path_pro):
        #     parser = ET.XMLParser(remove_blank_text=True)
        #     doc = ET.parse(filename_path_pro, parser)
        #     root = doc.getroot()
        #     child = root.find(".//path_input")
        #     if child is None:
        #         path_input = os.path.join(self.path_prj, r'/input')
        #     else:
        #         path_input = os.path.join(self.path_prj, child.text)
        # else:
        #     self.send_log.emit('Warning: ' + QCoreApplication.translate("StatModUseful", "The project is not saved. Save the project in the General tab."))
        project_properties = load_project_properties(self.path_prj)
        path_input = project_properties['path_input']

        return path_input

    def send_err_log(self):
        """
        This function sends the errors and the warnings to the logs.
        The stdout was redirected to self.mystdout before calling this function. It only sends the hundred first errors
        to avoid freezing the GUI. A similar function exists in sub_and_merge_GUI.py. Correct both if necessary.
        """
        max_send = 400
        if self.mystdout is not None:
            str_found = self.mystdout.getvalue()
        else:
            return
        str_found = str_found.split('\n')
        for i in range(0, min(len(str_found), max_send)):
            if len(str_found[i]) > 1:
                self.send_log.emit(str_found[i])
            if i == max_send - 1:
                self.send_log.emit(
                    self.fr('Warning: ') +
                    self.tr('Too many information for the GUI.'))

    def check_all_q(self):
        """
        This function checks the range of the different discharge and send a warning if we are out of the range
        estimated reasonable (based on the manual from Estimhab and FStress). This is not used by Stathab.

        It uses the variable self.qall which is a list of float composed of q1, q2, qsim1, qsim2, q50. This function
        only send warning and it used to check the entry before the calculation.
        """

        if self.qall[0] < self.qall[1]:
            q1 = self.qall[0]
            q2 = self.qall[1]
        else:
            q2 = self.qall[0]
            q1 = self.qall[1]

        if q2 < 2 * q1:
            self.send_log.emit(
                QCoreApplication.translate("StatModUseful", 'Warning: ') +
                QCoreApplication.translate(
                    "StatModUseful",
                    'Measured discharges are not very different. The results might '
                    'not be realistic. \n'))
        if (self.qall[4] < q1 / 10 or self.qall[4] > 5 * q2
            ) and self.qall[4] != -99:  # q50 not always necessary
            self.send_log.emit(
                QCoreApplication.translate("StatModUseful", 'Warning: ') +
                QCoreApplication.translate(
                    "StatModUseful",
                    'Q50 should be between q1/10 and 5*q2 for optimum results.'
                ))
        if self.qall[2] < q1 / 10 or self.qall[2] > 5 * q2:
            self.send_log.emit(
                QCoreApplication.translate("StatModUseful", 'Warning: ') +
                QCoreApplication.translate(
                    "StatModUseful",
                    'Discharge range should be between q1/10 and 5*q2 for optimum results (1).'
                ))
        if self.qall[3] < q1 / 10 or self.qall[3] > 5 * q2:
            self.send_log.emit(
                QCoreApplication.translate("StatModUseful", 'Warning: ') +
                QCoreApplication.translate(
                    "StatModUseful",
                    'Discharge range should be between q1/10 and 5*q2 for optimum results (2).'
                ))
class ImageDump(QWidget):
    def __init__(self, parent, title):

        super().__init__(parent)

        cwd = os.path.abspath(os.path.dirname(__file__))
        self._icons_path = os.path.join(cwd, 'icons')

        self.initUI(title)

    def initUI(self, title):

        ### Add toolbar to widget ###

        toolLayout = QBoxLayout(QBoxLayout.TopToBottom, self)
        toolLayout.setContentsMargins(0, 0, 0, 0)

        toolbar = QToolBar()
        toolLayout.addWidget(toolbar)

        ### Add contents ###

        vbox = QVBoxLayout()

        self.label = QLabel(self)
        self.label.setText(title)
        vbox.addWidget(self.label)

        self.list = QListWidget(self)
        self.list.setSelectionMode(
            self.list.ExtendedSelection)  #MultiSelection?
        self.list.setIconSize(QSize(60, 60))
        #self.list.setFlow( QListWidget.LeftToRight )
        #self.list.setResizeMode( QListWidget.Adjust ) # TODO: Finish QListWidget settings
        #self.list.setSpacing( 2 )
        #self.list.setViewMode( QListWidget.IconMode )
        vbox.addWidget(self.list)

        ### Put contents in outer toolLayout ###

        toolLayout.addLayout(vbox)
        toolLayout.setDirection(QBoxLayout.BottomToTop)

        ### Tools ###

        cwd = os.path.abspath(os.path.dirname(__file__))
        icons = os.path.join(cwd, 'icons')

        select_all_act = QtHelper.initAction(
            self,
            'Select All',
            self.selectAll,
            status='Select all images in the image set',
            icon='Select All.png')
        toolbar.addAction(select_all_act)

        toolbar.addSeparator()

        open_act = QtHelper.initAction(self,
                                       'Add Images',
                                       self.selectImages,
                                       status='Add images to the image set',
                                       icon='Images.png')
        toolbar.addAction(open_act)

        remove_act = QtHelper.initAction(
            self,
            'Remove Selected Images',
            self.removeSelected,
            status='Remove selected images from the image set',
            icon='Delete.png')
        toolbar.addAction(remove_act)

    def addItem(self, text):
        '''Adds a new QListWidgetItem with label "text".'''
        if len(self.list.findItems(text, Qt.MatchCaseSensitive)) == 0:
            item = QListWidgetItem(text)

            item.setIcon(QIcon(text))

            self.list.addItem(item)

    def removeItem(self, text):
        '''Remove all QListWidgetItems with label "text" (there should only ever be 1).'''
        for i in range(self.list.count() - 1, -1, -1):
            it = self.list.item(i)

            if it.text() == text:
                self.list.takeItem(i)

    def addItems(self, texts):
        '''Adds a QListWidgetItem labelled by each string in [texts]. Selects the added items.'''
        self.list.clearSelection()
        for text in texts:
            self.addItem(text)
            self.list.item(self.list.count() - 1).setSelected(True)
        self.list.sortItems()

    def removeItems(self, texts):
        '''Removes all items with labels contained in [texts].'''
        for i in range(self.list.count() - 1, -1, -1):
            it = self.list.item(i)

            if it.text() in texts:
                self.list.takeItem(i)

    def getSelected(self):
        '''Returns a list of text labels corresponding to the currently selected items.'''
        return [it.text() for it in list(self.list.selectedItems())]

    def removeSelected(self):
        '''Removes the items currently selected from the QListWidget.'''
        selected = self.getSelected()
        if len(selected) == 0:
            return

        msgBox = QMessageBox()
        msgBox.setText('Are you sure you want to remove the selected images?')
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        pressed = msgBox.exec_()

        if pressed == QMessageBox.Ok:
            for text in self.getSelected():
                self.removeItem(text)

    def selectAll(self):
        '''Selects all items in the QListWidget.'''
        if len(self.list.selectedItems()) == self.list.count():
            self.list.clearSelection()
        else:
            self.list.selectAll()

    def selectImages(self):
        '''Prompts the user for images and adds them to the current set.'''

        dialog = QFileDialog(self,
                             caption='Open Images',
                             directory=os.getcwd(),
                             filter='Images (*.png *.jpg)')
        dialog.setFileMode(QFileDialog.ExistingFiles)

        if dialog.exec_():
            filenames = dialog.selectedFiles()
        else:
            filenames = []

        self.addItems(filenames)
Пример #5
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        self.item_cnt = 0
        self.col = QColor(0, 0, 0)
        self.w = 1000
        self.h = 1000
        self.bezier_num = 3
        self.bspline_num = 4

        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, self.w, self.h)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(self.w, self.h)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget

        self.canvas_widget.setHorizontalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)
        self.canvas_widget.setVerticalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)

        # 设置菜单栏
        self.menubar = self.menuBar()
        file_menu = self.menubar.addMenu('文件')
        set_pen_act = file_menu.addAction('设置画笔')
        reset_canvas_act = file_menu.addAction('重置画布')
        save_canvas_act = file_menu.addAction('保存画布')
        exit_act = file_menu.addAction('退出')
        draw_menu = self.menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        edit_menu = self.menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')
        extra_menu = self.menubar.addMenu('附加功能')
        select_item = extra_menu.addAction('选择图元')
        fill_polygon = extra_menu.addAction('多边形填充')
        clip_polygon = extra_menu.addAction('多边形裁剪')
        cancel_item = extra_menu.addAction('撤销')
        copy_item = extra_menu.addAction('复制')
        paste_item = extra_menu.addAction('粘贴')

        # 连接信号和槽函数
        exit_act.triggered.connect(qApp.quit)
        set_pen_act.triggered.connect(self.set_pen_action)
        reset_canvas_act.triggered.connect(self.reset_canvas_action)
        save_canvas_act.triggered.connect(self.save_canvas_action)
        line_naive_act.triggered.connect(self.line_naive_action)
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)
        ellipse_act.triggered.connect(self.ellipse_action)
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)
        clip_cohen_sutherland_act.triggered.connect(
            self.clip_cohen_sutherland_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)
        select_item.triggered.connect(self.select_item_action)
        fill_polygon.triggered.connect(self.polygon_fill_action)
        clip_polygon.triggered.connect(self.polygon_clip_action)
        cancel_item.triggered.connect(self.cancel_item_action)
        copy_item.triggered.connect(self.copy_item_action)
        paste_item.triggered.connect(self.paste_item_action)
        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(self.w, self.h)
        self.setWindowTitle('CG Demo')

        self.setbar = QToolBar()
        self.addToolBar(Qt.LeftToolBarArea, self.setbar)

        self.bezier_box = QSpinBox()
        self.bezier_box.setRange(3, 20)
        self.bezier_box.setSingleStep(1)
        self.bezier_box.setValue(self.bezier_num)
        self.setbar.addWidget(QLabel("Bezier控制点数"))
        self.setbar.addWidget(self.bezier_box)
        self.setbar.addSeparator()
        self.bspline_box = QSpinBox()
        self.bspline_box.setRange(4, 20)
        self.bspline_box.setSingleStep(1)
        self.bspline_box.setValue(self.bspline_num)
        self.setbar.addWidget(QLabel("B样条阶数"))
        self.setbar.addWidget(self.bspline_box)
        self.bezier_box.valueChanged.connect(self.set_bezier_num)
        self.bspline_box.valueChanged.connect(self.set_bspline_num)

        self.w = 1000
        self.h = 1000
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, self.w, self.h)
        self.canvas_widget.resize(self.w, self.h)
        self.canvas_widget.setFixedSize(self.w, self.h)
        self.statusBar().showMessage('空闲')
        self.setMaximumHeight(self.h)
        self.setMaximumWidth(self.w)
        self.resize(self.w, self.h)

    def get_id(self):
        _id = str(self.item_cnt)
        self.item_cnt += 1
        return _id

    def remove_id(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1

    def set_bezier_num(self):
        self.bezier_num = self.bezier_box.value()
        self.canvas_widget.set_dot_num('Bezier', self.bezier_num)

    def set_bspline_num(self):
        self.bspline_num = self.bspline_box.value()
        self.canvas_widget.set_dot_num('B-spline', self.bspline_num)

    def set_pen_action(self):
        self.statusBar().showMessage('设置画笔')
        col = QColorDialog.getColor()
        if col.isValid():
            self.col = col
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def reset_canvas_action(self):
        self.item_cnt = 0
        self.statusBar().showMessage('重置画布')

        dialog = QDialog()
        dialog.setWindowTitle('重置画布')
        formlayout = QFormLayout(dialog)
        box1 = QSpinBox(dialog)
        box1.setRange(100, 1000)
        box1.setSingleStep(1)
        box1.setValue(self.w)
        slider1 = QSlider(Qt.Horizontal)
        slider1.setRange(100, 1000)
        slider1.setSingleStep(1)
        slider1.setValue(self.w)
        slider1.setTickPosition(QSlider.TicksBelow)
        slider1.setTickInterval(100)
        box2 = QSpinBox(dialog)
        box2.setRange(100, 1000)
        box2.setSingleStep(1)
        box2.setValue(self.h)
        slider2 = QSlider(Qt.Horizontal)
        slider2.setRange(100, 1000)
        slider2.setSingleStep(1)
        slider2.setValue(self.h)
        slider2.setTickPosition(QSlider.TicksBelow)
        slider2.setTickInterval(100)
        slider1.valueChanged.connect(box1.setValue)
        box1.valueChanged.connect(slider1.setValue)
        slider2.valueChanged.connect(box2.setValue)
        box2.valueChanged.connect(slider2.setValue)
        formlayout.addRow('Width:', box1)
        formlayout.addRow(slider1)
        formlayout.addRow('Height:', box2)
        formlayout.addRow(slider2)

        box3 = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        box3.accepted.connect(dialog.accept)
        box3.rejected.connect(dialog.reject)
        formlayout.addRow(box3)

        if dialog.exec():
            if (box1.value() < 100 or box1.value() > 1000 or box2.value() < 100
                    or box2.value() > 1000):
                QMessageBox.about(self, "提示", "修改失败,请保证输入的数字大于等于100小于等于1000")
            else:
                self.w = box1.value()
                self.h = box2.value()
            self.canvas_widget.clear_canvas()
            self.list_widget.clearSelection()
            self.canvas_widget.clear_selection()
            self.list_widget.clear()
            self.scene = QGraphicsScene(self)
            self.scene.setSceneRect(0, 0, self.w, self.h)
            self.canvas_widget.resize(self.w, self.h)
            self.canvas_widget.setFixedSize(self.w, self.h)
            self.statusBar().showMessage('空闲')
            self.setMaximumHeight(self.h)
            self.setMaximumWidth(self.w)
            self.resize(self.w, self.h)
            self.canvas_widget.undo_num = 0
            self.canvas_widget.undo_save = []

    def save_canvas_action(self):
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        self.statusBar().showMessage('保存画布')
        dialog = QFileDialog()
        filename = dialog.getSaveFileName(
            filter="Image Files(*.jpg *.png *.bmp)")
        if filename[0]:
            self.canvas_widget.save_canvas(filename[0], self.w, self.h)
            #res=self.canvas_widget.grab(self.canvas_widget.sceneRect().toRect())
            #res.save(filename[0])

    def line_naive_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_line('Naive', self.get_id())
        self.statusBar().showMessage('Naive算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_dda_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_line('DDA', self.get_id())
        self.statusBar().showMessage('DDA算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_line('Bresenham', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def ellipse_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_ellipse(self.get_id())
        self.statusBar().showMessage('中点圆生成算法绘制椭圆')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_dda_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_polygon('DDA', self.get_id())
        self.statusBar().showMessage('DDA算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_bresenham_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_polygon('Bresenham', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        '''text, ok = QInputDialog.getText(self, 'Bezier算法绘制曲线', '请输入控制点数目:')
        if ok:
            n=int(str(text))
        else:
            return
        if(n<=1):
            QMessageBox.about(self, "提示", "请保证输入的数字大于1")
            return'''

        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_curve('Bezier', self.get_id(),
                                            self.bezier_num)
        self.statusBar().showMessage('Bezier算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        '''text, ok = QInputDialog.getText(self, 'B-spline算法绘制曲线', '请输入控制点数目:')
        if ok:
            n=int(str(text))
        else:
            return
        if(n<=3):
            QMessageBox.about(self, "提示", "请保证输入的数字大于3")
            return'''

        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_curve('B-spline', self.get_id(),
                                            self.bspline_num)
        self.statusBar().showMessage('B-spline算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def translate_action(self):
        self.canvas_widget.start_translate()
        self.statusBar().showMessage('平移')

    def rotate_action(self):
        self.canvas_widget.start_rotate()
        self.statusBar().showMessage('旋转')

    def scale_action(self):
        self.canvas_widget.start_scale()
        self.statusBar().showMessage('缩放')

    def clip_cohen_sutherland_action(self):
        self.canvas_widget.start_clip('Cohen-Sutherland')
        self.statusBar().showMessage('裁剪')

    def clip_liang_barsky_action(self):
        self.canvas_widget.start_clip('Liang-Barsky')
        self.statusBar().showMessage('裁剪')

    def select_item_action(self):
        self.canvas_widget.start_select()
        self.statusBar().showMessage('选择图元')

    def copy_item_action(self):
        self.canvas_widget.start_copy()
        self.statusBar().showMessage('复制')

    def paste_item_action(self):
        self.canvas_widget.start_paste()
        self.statusBar().showMessage('粘贴')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def cancel_item_action(self):
        self.statusBar().showMessage('撤销')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        #self.canvas_widget.start_cancel(self.item_cnt)
        self.canvas_widget.start_undo()

    def polygon_clip_action(self):
        self.canvas_widget.start_clip_polygon()
        self.statusBar().showMessage('多边形裁剪')

    def polygon_fill_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_fill_polygon(self.get_id())
        self.statusBar().showMessage('多边形填充')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
Пример #6
0
class WallpaperWidget(QWizardPage):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setSubTitle(self.tr("<h2>Choose Wallpaper</h2>"))

        vlayout = QVBoxLayout(self)

        labelLayout = QHBoxLayout()
        labelImage = QLabel()
        labelImage.setMaximumSize(64, 64)
        labelImage.setPixmap(
            QIcon.fromTheme("preferences-desktop-wallpaper").pixmap(64, 64))
        labelLayout.addWidget(labelImage)

        label = QLabel(self)
        label.setText(
            self.
            tr("<p>Choose your favorite wallpaper for Pisi Linux. Don't forget to check out \
        <strong>Desktop Settings</strong> for downloading new and cool wallpapers.</p>"
               ))
        label.setWordWrap(True)
        labelLayout.addWidget(label)
        vlayout.addLayout(labelLayout)

        vlayout.addItem(
            QSpacerItem(20, 40, QSizePolicy.Preferred, QSizePolicy.Preferred))

        groupBox = QGroupBox(self)
        groupBox.setTitle(self.tr("Wallpapers"))
        groupBox.setMinimumHeight(350)

        grLayout = QVBoxLayout(groupBox)
        self.listWidget = QListWidget()
        self.listWidget.setViewMode(QListView.IconMode)
        self.listWidget.setIconSize(QSize(250, 150))
        grLayout.addWidget(self.listWidget)
        vlayout.addWidget(groupBox)

        vlayout.addItem(
            QSpacerItem(20, 40, QSizePolicy.Preferred, QSizePolicy.Preferred))

        hlayout = QHBoxLayout()
        self.button = QPushButton()
        self.button.setText(self.tr("Choose wallpaper from file"))
        hlayout.addWidget(self.button)

        hlayout.addItem(
            QSpacerItem(400, 20, QSizePolicy.Preferred, QSizePolicy.Preferred))

        self.checkbox = QCheckBox()
        self.checkbox.setText(self.tr("Don't change wallpaper"))
        hlayout.addWidget(self.checkbox)

        vlayout.addLayout(hlayout)

        self.checkbox.clicked.connect(self.wallpaperChecked)
        self.button.clicked.connect(self.wallpaperSelectDialog)
        self.listWidget.itemClicked.connect(self.wallpaperSelect)

        self.selectWallpaper = None
        self.wallpapersParser()

    def wallpapersParser(self):
        wallpaperPath = "/usr/share/wallpapers"
        for folder in os.listdir(wallpaperPath):
            path = join(wallpaperPath, folder, "contents")
            thumbFolder = os.listdir(path)
            for thumb in thumbFolder:
                if thumb.startswith("scre"):
                    item = QListWidgetItem(self.listWidget)

                    pix = QPixmap(join(path, thumb))
                    pix = pix.scaled(QSize(240, 140), Qt.IgnoreAspectRatio,
                                     Qt.FastTransformation)

                    item.setIcon(QIcon(pix))
                    item.setSizeHint(QSize(250, 150))
                    item.screenshotPath = join(path, thumb)

    def wallpaperSelect(self, item):
        if hasattr(item, "userSelect"):
            self.selectWallpaper = item.screenshotPath
        else:
            path = join(dirname(abspath(item.screenshotPath)), "images")
            list = os.listdir(path)
            list.sort()
            self.selectWallpaper = join(path, list[-1])

    def wallpaperChecked(self):
        if self.checkbox.isChecked():
            self.selectWallpaper = None
            self.listWidget.setDisabled(True)
            self.button.setDisabled(True)
        else:
            self.listWidget.clearSelection()
            self.listWidget.setEnabled(True)
            self.button.setEnabled(True)

    def wallpaperSelectDialog(self):
        file_url, file_type = QFileDialog.getOpenFileName(
            self, self.tr("Choose wallpaper"), QDir.homePath(),
            "Image (*.png *.jpg)")
        print(file_url)
        if not "" == file_url:
            self.selectWallpaper = file_url
            item = QListWidgetItem(self.listWidget)
            item.setIcon(QIcon(file_url))
            item.screenshotPath = file_url
            item.userSelect = True
            self.listWidget.setCurrentItem(item)

    def execute(self):
        configFilePath = join(QDir.homePath(), ".config",
                              "plasma-org.kde.plasma.desktop-appletsrc")

        parser = Parser(configFilePath)
        getWallpaper = parser.getWallpaper()

        if self.selectWallpaper:
            if "file://" + self.selectWallpaper != getWallpaper[2]:
                parser.setWallpaper("file://" + self.selectWallpaper)

        wp_isin = False
        appletsrc = open(configFilePath).readlines()
        for lines in appletsrc:
            if "Wallpaper" in lines:
                wp_isin = True

        wp = "\n[Containments][52][Wallpaper][org.kde.image][General]\nImage=file://{!s}\n".format(
            self.selectWallpaper)

        if wp_isin:
            if self.selectWallpaper:
                if "file://" + self.selectWallpaper != getWallpaper[1]:
                    parser.setWallpaper("file://" + self.selectWallpaper)

        else:
            if self.selectWallpaper:
                with open(configFilePath, "a") as rcfile:
                    rcfile.write(wp)
Пример #7
0
class SpellCheckDialog(QDialog):
    """Dialog to perform and control the spell check operation.
    """
    misspellFound = pyqtSignal()
    changeRequest = pyqtSignal(str)

    def __init__(self, spellCheckInterface, parent=None):
        """Create the dialog.

        Arguments:
            spellCheckInterface -- a reference to the spell engine interface
            parent -- the parent dialog
        """
        super().__init__(parent)
        self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint
                            | Qt.WindowCloseButtonHint)
        self.setWindowTitle(_('Spell Check'))
        self.spellCheckInterface = spellCheckInterface
        self.textLineIter = None
        self.textLine = ''
        self.replaceAllDict = {}
        self.tmpIgnoreWords = set()
        self.word = ''
        self.postion = 0

        topLayout = QHBoxLayout(self)
        leftLayout = QVBoxLayout()
        topLayout.addLayout(leftLayout)
        wordBox = QGroupBox(_('Not in Dictionary'))
        leftLayout.addWidget(wordBox)
        wordLayout = QVBoxLayout(wordBox)
        label = QLabel(_('Word:'))
        wordLayout.addWidget(label)
        self.wordEdit = QLineEdit()
        wordLayout.addWidget(self.wordEdit)
        self.wordEdit.textChanged.connect(self.updateFromWord)
        wordLayout.addSpacing(5)
        label = QLabel(_('Context:'))
        wordLayout.addWidget(label)
        self.contextEdit = SpellContextEdit()
        wordLayout.addWidget(self.contextEdit)
        self.contextEdit.textChanged.connect(self.updateFromContext)

        suggestBox = QGroupBox(_('Suggestions'))
        leftLayout.addWidget(suggestBox)
        suggestLayout = QVBoxLayout(suggestBox)
        self.suggestList = QListWidget()
        suggestLayout.addWidget(self.suggestList)
        self.suggestList.itemDoubleClicked.connect(self.replace)

        rightLayout = QVBoxLayout()
        topLayout.addLayout(rightLayout)
        ignoreButton = QPushButton(_('Ignor&e'))
        rightLayout.addWidget(ignoreButton)
        ignoreButton.clicked.connect(self.ignore)
        ignoreAllButton = QPushButton(_('&Ignore All'))
        rightLayout.addWidget(ignoreAllButton)
        ignoreAllButton.clicked.connect(self.ignoreAll)
        rightLayout.addStretch()
        addButton = QPushButton(_('&Add'))
        rightLayout.addWidget(addButton)
        addButton.clicked.connect(self.add)
        addLowerButton = QPushButton(_('Add &Lowercase'))
        rightLayout.addWidget(addLowerButton)
        addLowerButton.clicked.connect(self.addLower)
        rightLayout.addStretch()
        replaceButton = QPushButton(_('&Replace'))
        rightLayout.addWidget(replaceButton)
        replaceButton.clicked.connect(self.replace)
        self.replaceAllButton = QPushButton(_('Re&place All'))
        rightLayout.addWidget(self.replaceAllButton)
        self.replaceAllButton.clicked.connect(self.replaceAll)
        rightLayout.addStretch()
        cancelButton = QPushButton(_('&Cancel'))
        rightLayout.addWidget(cancelButton)
        cancelButton.clicked.connect(self.reject)
        self.widgetDisableList = [
            ignoreButton, ignoreAllButton, addButton, addLowerButton,
            self.suggestList
        ]
        self.fullDisableList = (self.widgetDisableList +
                                [self.replaceAllButton, self.wordEdit])

    def startSpellCheck(self, textLineIter):
        """Spell check text lines given in the iterator.

        Block execution except for the dialog if mispellings are found.
        Return True if spell check completes, False if cancelled.
        Arguments:
            textLineIter -- an iterator of text lines to check
        """
        self.textLineIter = textLineIter
        try:
            self.textLine = next(self.textLineIter)
        except StopIteration:
            return True
        if self.spellCheck():
            if self.exec_() == QDialog.Rejected:
                return False
        return True

    def continueSpellCheck(self):
        """Check lines, starting with current line.

        Exit the dialog if there are no more lines to check.
        """
        if not self.spellCheck():
            self.accept()

    def spellCheck(self):
        """Step through the iterator and spell check the lines.

        If results found, update the dialog with the results and return True.
        Return false if the end of the iterator is reached.
        """
        while True:
            results = self.spellCheckInterface.checkLine(
                self.textLine, self.tmpIgnoreWords)
            if results:
                self.word, self.position, suggestions = results[0]
                newWord = self.replaceAllDict.get(self.word, '')
                if newWord:
                    self.textLine = self.replaceWord(newWord)
                    self.changeRequest.emit(self.textLine)
                else:
                    self.misspellFound.emit()
                    self.setWord(suggestions)
                    return True
            try:
                self.textLine = next(self.textLineIter)
                self.tmpIgnoreWords.clear()
            except StopIteration:
                return False

    def setWord(self, suggestions):
        """Set dialog contents from the checked line and spell check results.
        
        Arguments:
            suggestions -- a list of suggested replacement words
        """
        self.wordEdit.blockSignals(True)
        self.wordEdit.setText(self.word)
        self.wordEdit.blockSignals(False)
        self.contextEdit.blockSignals(True)
        self.contextEdit.setPlainText(self.textLine)
        self.contextEdit.setSelection(self.position,
                                      self.position + len(self.word))
        self.contextEdit.blockSignals(False)
        self.suggestList.clear()
        self.suggestList.addItems(suggestions)
        self.suggestList.setCurrentItem(self.suggestList.item(0))
        for widget in self.fullDisableList:
            widget.setEnabled(True)

    def replaceWord(self, newWord):
        """Return textLine with word replaced with newWord.
        
        Arguments:
            newWord -- the replacement word
        """
        return (self.textLine[:self.position] + newWord +
                self.textLine[self.position + len(self.word):])

    def ignore(self):
        """Set word to ignored (this check only) and continue spell check.
        """
        self.tmpIgnoreWords.add(self.word)
        self.continueSpellCheck()

    def ignoreAll(self):
        """Add to dictionary's ignore list and continue spell check.
        """
        self.spellCheckInterface.acceptWord(self.word)
        self.continueSpellCheck()

    def add(self):
        """Add misspelling to dictionary and continue spell check"""
        self.spellCheckInterface.addToDict(self.word, False)
        self.continueSpellCheck()

    def addLower(self):
        """Add misspelling to dictionary as lowercase and continue spell check.
        """
        self.spellCheckInterface.addToDict(self.word, True)
        self.continueSpellCheck()

    def replace(self):
        """Replace misspelled word with suggestion or context edit box
        
        Then continue spell check.
        """
        if self.suggestList.isEnabled():
            newWord = self.suggestList.currentItem().text()
            self.textLine = self.replaceWord(newWord)
        else:
            self.textLine = self.contextEdit.toPlainText()
        self.changeRequest.emit(self.textLine)
        self.continueSpellCheck()

    def replaceAll(self):
        """Replace misspelled word with suggestion or word edit (in future too).
        
        Stores changed word in replaceAllDict and continues spell check.
        """
        if self.suggestList.isEnabled():
            newWord = self.suggestList.currentItem().text()
        else:
            newWord = self.wordEdit.text()
        self.textLine = self.replaceWord(newWord)
        self.replaceAllDict[self.word] = newWord
        self.changeRequest.emit(self.textLine)
        self.continueSpellCheck()

    def updateFromWord(self):
        """Update dialog after word line editor change.
        
        Disables suggests and ignore/add controls. Updates the context editor.
        """
        for widget in self.widgetDisableList:
            widget.setEnabled(False)
        newWord = self.wordEdit.text()
        self.suggestList.clearSelection()
        self.contextEdit.blockSignals(True)
        self.contextEdit.setPlainText(self.replaceWord(newWord))
        self.contextEdit.setSelection(self.position,
                                      self.position + len(newWord))
        self.contextEdit.blockSignals(False)

    def updateFromContext(self):
        """Update dialog after context editor change.
        
        Disables controls except for replace.
        """
        for widget in self.fullDisableList:
            widget.setEnabled(False)
        self.suggestList.clearSelection()
Пример #8
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()

        # 使用QListWidget来记录已有的图元,并用于选择图元。
        #注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(600, 600)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget
        self.canvas_widget.setHorizontalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)
        self.canvas_widget.setVerticalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)

        # 设置菜单栏
        menubar = self.menuBar()

        file_menu = menubar.addMenu('文件')
        set_pen_act = file_menu.addAction('设置画笔')
        reset_canvas_act = file_menu.addAction('重置画布')
        save_canvas_act = file_menu.addAction('保存画布')
        exit_act = file_menu.addAction('退出')

        draw_menu = menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')

        edit_menu = menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')

        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')

        # 连接信号和槽函数
        set_pen_act.triggered.connect(self.set_pen_action)
        reset_canvas_act.triggered.connect(self.reset_canvas_action)
        save_canvas_act.triggered.connect(self.save_canvas_action)
        exit_act.triggered.connect(self.exit_action)

        line_naive_act.triggered.connect(self.line_naive_action)
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)

        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)

        ellipse_act.triggered.connect(self.ellipse_action)

        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)

        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)

        clip_cohen_sutherland_act.triggered.connect(
            self.clip_cohen_sutherland_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)

        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(600, 600)
        self.setWindowTitle('CG Demo')

    def set_pen_action(self):
        self.statusBar().showMessage('设置画笔')
        color = QColorDialog.getColor()
        self.canvas_widget.set_pen_color(color)
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def reset_canvas_action(self):
        self.statusBar().showMessage('重置画布')

        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(600, 600)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget
        self.canvas_widget.setHorizontalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)
        self.canvas_widget.setVerticalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)

        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)

        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.resize(600, 600)
        self.setWindowTitle('CG Demo')

    def save_canvas_action(self):
        self.statusBar().showMessage('保存画布')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        file_dialog = QFileDialog()
        filename = file_dialog.getSaveFileName(
            filter="Image Files(*.jpg *.png *.bmp)")
        if filename[0]:
            ret = self.canvas_widget.grab(
                self.canvas_widget.sceneRect().toRect())
            ret.save(filename[0])

    def exit_action(self):
        self.statusBar().showMessage('退出')
        reply = QMessageBox.question(self, "CG Demo", "是否保存画布",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.save_canvas_action()
        qApp.quit()

    def line_naive_action(self):
        self.statusBar().showMessage('Naive算法绘制线段')
        self.canvas_widget.start_draw('line', 'Naive')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_dda_action(self):
        self.statusBar().showMessage('DDA算法绘制线段')
        self.canvas_widget.start_draw('line', 'DDA')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.canvas_widget.start_draw('line', 'Bresenham')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def ellipse_action(self):
        self.statusBar().showMessage('中点圆算法绘制椭圆')
        self.canvas_widget.start_draw('ellipse')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_dda_action(self):
        self.statusBar().showMessage('DDA算法绘制多边形')
        self.canvas_widget.start_draw('polygon', 'DDA')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_bresenham_action(self):
        self.statusBar().showMessage('Bresenham算法绘制多边形')
        self.canvas_widget.start_draw('polygon', 'Bresenham')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        self.statusBar().showMessage('Bezier算法绘制曲线')
        self.canvas_widget.start_draw('curve', 'Bezier')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        self.statusBar().showMessage('B-spline算法绘制曲线')
        self.canvas_widget.start_draw('curve', 'B-spline')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def translate_action(self):
        self.statusBar().showMessage('平移')
        self.canvas_widget.start_modify('translate')

    def rotate_action(self):
        self.statusBar().showMessage('旋转')
        self.canvas_widget.start_modify('rotate')

    def scale_action(self):
        self.statusBar().showMessage('缩放')
        self.canvas_widget.start_modify('scale')

    def clip_cohen_sutherland_action(self):
        self.statusBar().showMessage('Cohen_Sutherland算法裁剪')
        self.canvas_widget.start_modify('clip', 'Cohen-Sutherland')

    def clip_liang_barsky_action(self):
        self.statusBar().showMessage('Liang_Barsky算法裁剪')
        self.canvas_widget.start_modify('clip', 'Liang-Barsky')
Пример #9
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        self.item_cnt = 0
        # TODO: 区分长宽
        # self.size = 900
        self.length = 800
        self.width = 800
        self.is_modified = False
        self.opened_filename = ''

        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(150)
        # self.list_widget.setMaximumWidth(150)
        # self.list_widget.setFixedWidth(150)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, self.length, self.width)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(self.length, self.width)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget

        # 设置菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')
        set_pen_act = file_menu.addAction('设置画笔')
        open_canvas_act = file_menu.addAction('打开画布')
        open_canvas_act.setShortcut('Ctrl+O')
        reset_canvas_act = file_menu.addAction('重置画布')
        reset_canvas_act.setShortcut('Ctrl+R')
        save_canvas_act = file_menu.addAction('保存画布')
        save_canvas_act.setShortcut('Ctrl+S')
        export_canvas_act = file_menu.addAction('导出画布')
        export_canvas_act.setShortcut('Ctrl+E')
        exit_act = file_menu.addAction('退出')
        draw_menu = menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        freedom_act = draw_menu.addAction('自由绘图')
        edit_menu = menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        delete_act = edit_menu.addAction('删除')
        delete_act.setShortcut('Delete')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')

        # 连接信号和槽函数
        exit_act.triggered.connect(self.my_quit)
        # exit_act.triggered.connect(self.close)
        set_pen_act.triggered.connect(self.set_pen_action)
        open_canvas_act.triggered.connect(self.open_canvas_action)
        reset_canvas_act.triggered.connect(lambda: self.reset_canvas_action())
        save_canvas_act.triggered.connect(self.save_canvas_action)
        export_canvas_act.triggered.connect(self.export_canvas_action)
        line_naive_act.triggered.connect(self.line_naive_action)
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)
        ellipse_act.triggered.connect(self.ellipse_action)
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)
        clip_cohen_sutherland_act.triggered.connect(
            self.clip_cohen_sutherland_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)
        delete_act.triggered.connect(self.delete_action)
        freedom_act.triggered.connect(self.freedom_action)
        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        # self.resize(self.size, self.size)
        self.resize(self.length, self.width)
        self.setWindowTitle('CG Demo')

    def get_id(self, add):
        # _id = str(self.item_cnt)
        if add:
            self.item_cnt += 1
        _id = str(self.item_cnt)
        return _id

    def set_pen_action(self):
        temp_color = QColorDialog.getColor()
        if temp_color.isValid():
            self.canvas_widget.temp_color = temp_color

    def open_canvas_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.statusBar().showMessage('打开画布')
        if len(self.canvas_widget.item_dict) > 0 or self.is_modified:
            reply = QMessageBox.question(
                self, '是否保存', '是否保存当前草稿?',
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                QMessageBox.Yes)
            # print(reply)
            if reply == QMessageBox.Yes:
                self.save_canvas_action()
            elif reply == QMessageBox.Cancel:
                return
        self.reset_canvas_action(False)
        self.statusBar().showMessage('打开画布')
        path = QFileDialog.getOpenFileName(caption='打开画布',
                                           filter='画布文件 (*.canvas)')
        # print(path[0])
        self.opened_filename = path[0]
        if path[0] != '':
            fr = open(path[0], 'rb')
            open_list = pickle.load(fr)
            for item in open_list:
                color = QColor(item[4][0], item[4][1], item[4][2])
                temp_item = MyItem(item[0], item[1], item[2], item[3], color)
                self.canvas_widget.scene().addItem(temp_item)
                self.list_widget.addItem(item[0])
                self.canvas_widget.item_dict[item[0]] = temp_item
            fr.close()
            self.item_cnt = len(open_list)
            name = self.opened_filename.split('/')[-1].split('.')[0]
            self.setWindowTitle('CG Demo - ' + name)

    def reset_canvas_action(self, resize=True):
        # print(resize)
        if resize:
            self.length = QInputDialog.getInt(self, '请输入', '长度', 800, 200,
                                              1500)[0]
            self.width = QInputDialog.getInt(self, '请输入', '宽度', 800, 200,
                                             900)[0]
        self.list_widget.clearSelection()
        self.list_widget.clear()
        self.canvas_widget.clear_selection()
        self.canvas_widget.item_dict.clear()
        self.canvas_widget.scene().clear()
        self.item_cnt = 0
        self.canvas_widget.status = ''
        self.opened_filename = ''
        self.is_modified = False
        # TODO: 设置长宽
        self.scene.setSceneRect(0, 0, self.length, self.width)
        self.canvas_widget.setFixedSize(self.length, self.width)
        self.setWindowTitle('CG Demo')
        # self.resize(self.length, self.width)
        # self.canvas_widget.updateScene([self.canvas_widget.sceneRect()])

    def save_canvas_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.statusBar().showMessage('保存画布')
        save_list = []
        if self.opened_filename == '':
            path = QFileDialog.getSaveFileName(caption='保存画布',
                                               filter='画布文件 (*.canvas)')
            # print(path[0])
            if path[0] != '':
                for item in self.canvas_widget.item_dict.values():
                    save_list.append([
                        item.id, item.item_type, item.p_list, item.algorithm,
                        item.color.getRgb()
                    ])
                fw = open(path[0], 'wb')
                pickle.dump(save_list, fw)
                fw.close()
                self.opened_filename = path[0]
                self.is_modified = False
                name = self.opened_filename.split('/')[-1].split('.')[0]
                self.setWindowTitle('CG Demo - ' + name)
        else:
            for item in self.canvas_widget.item_dict.values():
                save_list.append([
                    item.id, item.item_type, item.p_list, item.algorithm,
                    item.color.getRgb()
                ])
            fw = open(self.opened_filename, 'wb')
            pickle.dump(save_list, fw)
            fw.close()
            self.is_modified = False

    def export_canvas_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.statusBar().showMessage('导出画布')
        # TODO: 区分长宽
        self.start_export(self.length, self.width)

    def my_quit(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        if self.is_modified:
            reply = QMessageBox.question(
                self, '退出 - 是否保存', '是否保存当前草稿?',
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.save_canvas_action()
                qApp.quit()
            elif reply == QMessageBox.No:
                qApp.quit()
        else:
            qApp.quit()

    def line_naive_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_draw_line('Naive', self.get_id(False))
        self.statusBar().showMessage('Naive算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_dda_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_draw_line('DDA', self.get_id(False))
        self.statusBar().showMessage('DDA算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_draw_line('Bresenham', self.get_id(False))
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_dda_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_draw_polygon('DDA', self.get_id(False))
        self.statusBar().showMessage('DDA算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_bresenham_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_draw_polygon('Bresenham', self.get_id(False))
        self.statusBar().showMessage('Bresenham算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def ellipse_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_draw_ellipse('Midpoint-circle',
                                              self.get_id(False))
        self.statusBar().showMessage('中点生成算法绘制椭圆')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_draw_curve('Bezier', self.get_id(False))
        self.statusBar().showMessage('Bezier曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_draw_curve('B-spline', self.get_id(False))
        self.statusBar().showMessage('B-spline曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def translate_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_translate()
        self.statusBar().showMessage('平移')

    def rotate_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_rotate()
        self.statusBar().showMessage('旋转')

    def scale_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_scale()
        self.statusBar().showMessage('缩放')

    def clip_cohen_sutherland_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_clip('Cohen-Sutherland')
        self.statusBar().showMessage('Cohen-Sutherland裁剪')

    def clip_liang_barsky_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_clip('Liang-Barsky')
        self.statusBar().showMessage('Liang-Barsky裁剪')

    def delete_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_delete()
        self.statusBar().showMessage('删除')

    def freedom_action(self):
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        self.canvas_widget.start_freedom(self.get_id(False))
        self.statusBar().showMessage('自由绘图')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def start_export(self, length, width):
        # TODO: 区分长宽
        path = QFileDialog.getSaveFileName(
            caption='导出画布',
            filter='BMP图像 (*.bmp);;PNG图像 (*.png);;JPEG图像 (*.jpg)')
        # print(path)
        if path[0] != '':
            canvas = np.zeros([width, length, 3], np.uint8)
            canvas.fill(255)
            for item in self.canvas_widget.item_dict.values():
                if item.item_type == 'line':
                    pixels = alg.draw_line(item.p_list, item.algorithm)
                    temp_color = item.color.getRgb()
                    pen_color = np.zeros(3, np.uint8)
                    pen_color[0], pen_color[1], pen_color[2] = temp_color[
                        0], temp_color[1], temp_color[2]
                    for x, y in pixels:
                        if 0 <= x < length and 0 <= y < width:
                            canvas[y, x] = np.array(pen_color)
                elif item.item_type == 'polygon':
                    pixels = alg.draw_polygon(item.p_list, item.algorithm)
                    temp_color = item.color.getRgb()
                    pen_color = np.zeros(3, np.uint8)
                    pen_color[0], pen_color[1], pen_color[2] = temp_color[
                        0], temp_color[1], temp_color[2]
                    for x, y in pixels:
                        if 0 <= x < length and 0 <= y < width:
                            canvas[y, x] = np.array(pen_color)
                elif item.item_type == 'ellipse':
                    pixels = alg.draw_ellipse(item.p_list)
                    temp_color = item.color.getRgb()
                    pen_color = np.zeros(3, np.uint8)
                    pen_color[0], pen_color[1], pen_color[2] = temp_color[
                        0], temp_color[1], temp_color[2]
                    for x, y in pixels:
                        if 0 <= x < length and 0 <= y < width:
                            canvas[y, x] = np.array(pen_color)
                elif item.item_type == 'curve':
                    pixels = alg.draw_curve(item.p_list, item.algorithm)
                    temp_color = item.color.getRgb()
                    pen_color = np.zeros(3, np.uint8)
                    pen_color[0], pen_color[1], pen_color[2] = temp_color[
                        0], temp_color[1], temp_color[2]
                    for x, y in pixels:
                        if 0 <= x < length and 0 <= y < width:
                            canvas[y, x] = np.array(pen_color)
                elif item.item_type == 'freedom':
                    pixels = []
                    for i in range(len(item.p_list) - 1):
                        pixels.extend(
                            alg.draw_line([item.p_list[i], item.p_list[i + 1]],
                                          'Bresenham'))
                    temp_color = item.color.getRgb()
                    pen_color = np.zeros(3, np.uint8)
                    pen_color[0], pen_color[1], pen_color[2] = temp_color[
                        0], temp_color[1], temp_color[2]
                    for x, y in pixels:
                        if 0 <= x < length and 0 <= y < width:
                            canvas[y, x] = np.array(pen_color)
                if path[1] == 'BMP图像 (*.bmp)':
                    Image.fromarray(canvas).save(path[0], 'bmp')
                elif path[1] == 'PNG图像 (*.png)':
                    Image.fromarray(canvas).save(path[0], 'png')
                else:
                    Image.fromarray(canvas).save(path[0], 'jpeg', quality=95)

    def closeEvent(self, a0: QCloseEvent) -> None:
        if self.canvas_widget.status == 'polygon' or self.canvas_widget.status == 'curve':
            self.canvas_widget.finish_draw()
        if self.is_modified:
            reply = QMessageBox.question(
                self, '退出 - 是否保存', '是否保存当前草稿?',
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.save_canvas_action()
                a0.accept()
            elif reply == QMessageBox.Cancel:
                a0.ignore()
Пример #10
0
class WallpaperWidget(QWizardPage):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setSubTitle(self.tr("<h2>Choose Wallpaper</h2>"))

        vlayout = QVBoxLayout(self)

        labelLayout = QHBoxLayout()
        labelImage = QLabel()
        labelImage.setMaximumSize(64,64)
        labelImage.setPixmap(QIcon.fromTheme("preferences-desktop-wallpaper").pixmap(64, 64))
        labelLayout.addWidget(labelImage)

        label = QLabel(self)
        label.setText(self.tr("<p>Choose your favorite wallpaper for KaOS. Don't forget to check out \
        <strong>Desktop Settings</strong> for downloading new and cool wallpapers.</p>"))
        label.setWordWrap(True)
        labelLayout.addWidget(label)
        vlayout.addLayout(labelLayout)

        vlayout.addItem(QSpacerItem(20, 40, QSizePolicy.Preferred, QSizePolicy.Preferred))

        groupBox = QGroupBox(self)
        groupBox.setTitle(self.tr("Wallpapers"))
        groupBox.setMinimumHeight(350)

        grLayout = QVBoxLayout(groupBox)
        self.listWidget = QListWidget()
        self.listWidget.setViewMode(QListView.IconMode)
        self.listWidget.setIconSize(QSize(250, 150))
        grLayout.addWidget(self.listWidget)
        vlayout.addWidget(groupBox)

        vlayout.addItem(QSpacerItem(20, 40, QSizePolicy.Preferred, QSizePolicy.Preferred))

        hlayout = QHBoxLayout()
        self.button = QPushButton()
        self.button.setText(self.tr("Choose wallpaper from file"))
        hlayout.addWidget(self.button)

        hlayout.addItem(QSpacerItem(400, 20, QSizePolicy.Preferred, QSizePolicy.Preferred))

        self.checkbox = QCheckBox()
        self.checkbox.setText(self.tr("Don't change wallpaper"))
        hlayout.addWidget(self.checkbox)

        vlayout.addLayout(hlayout)

        self.checkbox.clicked.connect(self.wallpaperChecked)
        self.button.clicked.connect(self.wallpaperSelectDialog)
        self.listWidget.itemClicked.connect(self.wallpaperSelect)

        self.selectWallpaper = None
        self.wallpapersParser()

    def wallpapersParser(self):
        wallpaperPath = "/usr/share/wallpapers"
        for folder in os.listdir(wallpaperPath):
            path = join(wallpaperPath,folder, "contents")
            thumbFolder = os.listdir(path)
            for thumb in thumbFolder:
                if thumb.startswith("scre"):
                    item = QListWidgetItem(self.listWidget)

                    pix = QPixmap(join(path, thumb))
                    pix = pix.scaled(QSize(240, 140), Qt.IgnoreAspectRatio, Qt.FastTransformation)

                    item.setIcon(QIcon(pix))
                    item.setSizeHint(QSize(250, 150))
                    item.screenshotPath = join(path, thumb)

    def wallpaperSelect(self, item):
        if hasattr(item, "userSelect"):
            self.selectWallpaper = item.screenshotPath
        else:
            path = join(dirname(abspath(item.screenshotPath)), "images")
            list = os.listdir(path)
            list.sort()
            self.selectWallpaper = join(path, list[-1])

    def wallpaperChecked(self):
        if self.checkbox.isChecked():
            self.selectWallpaper = None
            self.listWidget.setDisabled(True)
            self.button.setDisabled(True)
        else:
            self.listWidget.clearSelection()
            self.listWidget.setEnabled(True)
            self.button.setEnabled(True)

    def wallpaperSelectDialog(self):
        file_url, file_type = QFileDialog.getOpenFileName(self, self.tr("Choose wallpaper"), QDir.homePath(), "Image (*.png *.jpg)")
        print(file_url)
        if not "" == file_url:
            self.selectWallpaper = file_url
            item = QListWidgetItem(self.listWidget)
            item.setIcon(QIcon(file_url))
            item.screenshotPath = file_url
            item.userSelect = True
            self.listWidget.setCurrentItem(item)

    def execute(self):
        configFilePath = join(QDir.homePath(), ".config", "plasma-org.kde.plasma.desktop-appletsrc")

        parser = Parser(configFilePath)
        getWallpaper = parser.getWallpaper()

        if self.selectWallpaper:
            if "file://"+self.selectWallpaper != getWallpaper[1]:
                parser.setWallpaper("file://"+self.selectWallpaper)
Пример #11
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        self.item_cnt = 0

        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(600, 600)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget

        # 设置菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')
        set_pen_act = file_menu.addAction('设置画笔')
        reset_canvas_act = file_menu.addAction('重置画布')
        save_canvas_act = file_menu.addAction('保存画布')
        exit_act = file_menu.addAction('退出')
        draw_menu = menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        edit_menu = menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')

        # 连接信号和槽函数
        exit_act.triggered.connect(qApp.quit)
        set_pen_act.triggered.connect(self.set_pen_action)
        reset_canvas_act.triggered.connect(self.reset_canvas_action)
        save_canvas_act.triggered.connect(self.save_canvas_action)
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)
        ellipse_act.triggered.connect(self.ellipse_action)
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)
        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(600, 600)
        self.setWindowTitle('CG Demo')

    def get_id(self):
        _id = str(self.item_cnt)
        self.item_cnt += 1
        return _id

    def set_pen_action(self):
        color = QColorDialog.getColor(self.canvas_widget.get_pen())
        self.canvas_widget.set_pen(color)

    def reset_canvas_action(self):
        self.item_cnt = 0
        self.canvas_widget.clear_canvas()
        self.statusBar().showMessage('重置画布')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        self.list_widget.clear()

    def save_canvas_action(self):
        result = QFileDialog.getSaveFileName(
            filter='Images (*.png *.jpg *.bmp)')
        self.canvas_widget.save_canvas(result[0])
        self.statusBar().showMessage('保存画布')

    def line_dda_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_line('DDA', self.get_id())
        self.statusBar().showMessage('DDA算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_line('Bresenham', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_dda_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_polygon('DDA', self.get_id())
        self.statusBar().showMessage('DDA算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_bresenham_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_polygon('Bresenham', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def ellipse_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_ellipse(self.get_id())
        self.statusBar().showMessage('中点圆生成算法绘制椭圆')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_curve('Bezier', self.get_id())
        self.statusBar().showMessage('Bezier算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_curve('B-spline', self.get_id())
        self.statusBar().showMessage('B-spline算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def translate_action(self):
        self.canvas_widget.start_translate()
        pass

    def rotate_action(self):
        self.canvas_widget.start_rotate()
        pass

    def scale_action(self):
        self.canvas_widget.start_scale()
        pass
Пример #12
0
class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.filenames = json_files()

        if type(self.filenames) is list:
            self.curr_file = self.filenames[0]
        else:
            self.curr_file = self.filenames

        self.initUI()

    def initUI(self):

        self.num = -1  # index for search bar query
        self.show_save = False  # bool for showing unsaved changes dialog
        self.temp_file = ".temp.csv"
        self.refresh_file = False  # failsafe 1 for itemChanged trigger

        self.list_1 = QListWidget()

        lister(file=self.curr_file, target=self.list_1, index=0, mode=0)
        self.list_1.clicked.connect(self.clear_selection)
        self.list_1.installEventFilter(self)

        self.list_items = self.list_1.count(
        )  # failsafe 2 for itemChanged trigger
        self.list_1.itemChanged.connect(self.edit_next_item)
        self.list_1.verticalScrollBar().valueChanged.connect(self.sync_scroll)

        self.list_2 = QListWidget()
        lister(file=self.curr_file, target=self.list_2, index=1, mode=0)
        self.list_2.clicked.connect(self.clear_selection)

        self.list_3 = QListWidget()
        lister(file=self.curr_file, target=self.list_3, index=2, mode=0)
        self.list_3.clicked.connect(self.clear_selection)

        self.all_lists = [self.list_1, self.list_2, self.list_3]

        self.menubar = QMenuBar()
        self.menubar.setNativeMenuBar(False)

        exit_event = QAction('Exit', self)
        exit_event.setShortcut('Ctrl+W')
        exit_event.triggered.connect(app.quit)

        showAct = QAction('Show extras', self, checkable=True)
        showAct.setChecked(False)
        showAct.setShortcut('Ctrl+E')
        showAct.triggered.connect(self.hide_notes)

        addAct = QAction('Fields', self)
        addAct.setShortcut('Ctrl+N')
        addAct.triggered.connect(self.add_item)

        fileOpen = QAction('Open file', self)
        fileOpen.triggered.connect(self.fileDialog)
        fileOpen.setShortcut('Ctrl+O')

        fileSave = QAction('Save file', self)
        fileSave.triggered.connect(self.save)
        fileSave.triggered.connect(self.refresh_recents)
        fileSave.setShortcut('Ctrl+S')

        self.fileRecents = QMenu('Recent file', self)
        self.refresh_recents()

        self.toggle_theme = QAction('Toggle theme', self, checkable=True)
        self.toggle_theme.setChecked(json_theme())
        self.toggle_theme.triggered.connect(self.theme)
        self.toggle_theme.setShortcut('Ctrl+T')

        self.col_sort_index = QMenu('Sorting column index', self)
        self.col_sort_index.addAction(QAction(str(0), self))
        self.col_sort_index.addAction(QAction(str(1), self))
        self.col_sort_index.addAction(QAction(str(2), self))
        self.col_sort_index.triggered.connect(self.sort_col_choice)

        self.col_search_index = QMenu('Searching column index', self)
        self.col_search_index.addAction(QAction(str(0), self))
        self.col_search_index.addAction(QAction(str(1), self))
        self.col_search_index.addAction(QAction(str(2), self))
        self.col_search_index.triggered.connect(self.search_col_choice)

        self.sort = QAction('Sort entries', self, checkable=True)
        self.curr_col = 0
        self.search_col = 0
        self.sort.triggered.connect(self.refresh_list)
        self.sort.setShortcut('Ctrl+R')

        self.addFields = self.menubar.addMenu('Add')
        self.addFields.addAction(addAct)

        self.optionMenu = self.menubar.addMenu('Options')
        self.optionMenu.addAction(exit_event)
        self.optionMenu.addAction(showAct)
        self.optionMenu.addAction(self.toggle_theme)
        self.optionMenu.addMenu(self.col_sort_index)
        self.optionMenu.addMenu(self.col_search_index)
        self.optionMenu.addAction(self.sort)

        self.fileMenu = self.menubar.addMenu('File')
        self.fileMenu.addAction(fileOpen)
        self.fileMenu.addAction(fileSave)
        self.fileMenu.addMenu(self.fileRecents)

        self.search_bar = QLineEdit()
        self.search_bar.setPlaceholderText('Search vocab')
        self.search_bar.setClearButtonEnabled(True)
        self.search_bar.setMaxLength(10)
        self.search_bar.returnPressed.connect(self.search_item)

        self.status_bar = QStatusBar()
        status(self.status_bar, self.list_1)

        grid = QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(self.menubar, 0, 0)
        grid.addWidget(self.list_1, 1, 0)
        grid.addWidget(self.list_2, 1, 1)
        grid.addWidget(self.list_3, 1, 2)
        grid.addWidget(self.search_bar, 0, 1)
        grid.addWidget(self.status_bar)

        self.theme()
        self.setLayout(grid)
        self.setGeometry(*json_window_size())
        self.setWindowTitle(f'{split_name(self.curr_file)}')
        self.show()

        self.list_1.scrollToBottom()
        self.list_2.verticalScrollBar().setHidden(True)
        self.list_3.verticalScrollBar().setHidden(True)
        self.list_3.setHidden(True)

    def sync_scroll(self):

        scroll_location = self.list_1.verticalScrollBar().value()

        self.list_2.verticalScrollBar().setValue(scroll_location)
        self.list_3.verticalScrollBar().setValue(scroll_location)

    def edit_next_item(self, event):
        """When an item is added and edited on the first col, starts editing its counterpart on the next col"""

        if self.list_items == self.list_1.count(
        ) - 2 or self.list_items != self.list_1.count(
        ) and self.refresh_file == False:

            item = self.list_2.item(self.list_2.count() - 1)
            self.list_2.editItem(item)

            self.list_items = self.list_1.count()

    def closeEvent(self, event):
        """Triggered upon program exit, shows a dialog for unsaved changes using a bool"""

        if self.show_save == True:

            reply = QMessageBox.question(
                self, 'Message',
                "You may have unsaved changes, are you sure you want to quit?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if reply == QMessageBox.Yes:
                try:
                    remove(self.temp_file)
                except:
                    pass

                event.accept()
            else:
                event.ignore()

        else:
            pass

    def sort_col_choice(self, action):
        self.curr_col = int(action.text())

    def search_col_choice(self, action):
        self.search_col = int(action.text())

    def refresh_list(self):
        """Refreshes the contents of the lists, when sorting is used"""

        self.save(
            mode=1
        )  # saves a temp copy, with changes, but irreversable sorting introduced

        clear_lists(self.all_lists)

        if self.sort.isChecked() == True:
            mode = 2
        else:
            mode = 0

        try:
            lister(file=self.temp_file,
                   target=self.list_1,
                   index=0,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.temp_file,
                   target=self.list_2,
                   index=1,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.temp_file,
                   target=self.list_3,
                   index=2,
                   mode=mode,
                   column=self.curr_col)

        except:
            lister(file=self.curr_file,
                   target=self.list_1,
                   index=0,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.curr_file,
                   target=self.list_2,
                   index=1,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.curr_file,
                   target=self.list_3,
                   index=2,
                   mode=mode,
                   column=self.curr_col)

    def refresh_recents(self):

        try:

            file_1 = QAction(self.curr_file, self)
            self.fileRecents.addAction(file_1)
            file_1.triggered.connect(self.clickedFileAct)

            if type(self.filenames) is list:

                if self.filenames[1] != None:
                    file_2 = QAction(self.filenames[1], self)
                    self.fileRecents.addAction(file_2)
                    file_2.triggered.connect(self.clickedFileAct)

                if self.filenames[2] != None:
                    file_3 = QAction(self.filenames[2], self)
                    self.fileRecents.addAction(file_3)
                    file_3.triggered.connect(self.clickedFileAct)

        except:
            pass

    def clickedFileAct(self):

        self.refresh_file = True

        file = self.sender().text()
        self.curr_file = file
        self.setWindowTitle(f'{split_name(self.curr_file)}')

        clear_lists(self.all_lists)

        lister(file=self.curr_file, target=self.list_1, index=0)
        lister(file=self.curr_file, target=self.list_2, index=1)
        lister(file=self.curr_file, target=self.list_3, index=2)

        status(self.status_bar, self.list_1)
        self.theme()

        self.list_1.scrollToBottom()
        self.list_3.setHidden(True)

        self.refresh_file = False

    def eventFilter(self, source, event):
        """Item (row) deletion"""

        if (event.type() == QEvent.ContextMenu and source is self.list_1):
            menu = QMenu()
            menu.addAction("Delete row")
            if menu.exec_(event.globalPos()):
                item = source.itemAt(event.pos())
                try:
                    model = self.list_1.indexFromItem(item)
                    row = model.row()

                    self.show_save = True

                    self.list_1.takeItem(row)
                    self.list_2.takeItem(row)
                    self.list_3.takeItem(row)

                    status(self.status_bar, self.list_1,
                           f'Deleted row number: {row+1}.')
                    self.clearSelection()

                except:
                    pass

            return True
        return super(Example, self).eventFilter(source, event)

    def hide_notes(self):
        """Toggles showing the note column and stretches the window for clearer reading of it"""

        self.list_3.setHidden(not self.list_3.isHidden())

    def theme(self):
        """Sets the theme for the window and its widgets"""

        palette = QPalette()

        # dark theme
        if self.toggle_theme.isChecked() == True:

            palette.setColor(QPalette.Window, QColor(0, 0, 0))
            dark = "background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"

            self.menubar.setStyleSheet(dark)
            self.addFields.setStyleSheet(dark)
            self.optionMenu.setStyleSheet(dark)
            self.fileMenu.setStyleSheet(dark)
            self.search_bar.setStyleSheet(
                "background-color: rgb(0, 0, 0); color: rgb(255, 255, 255)"
            )  # border: 0px; for transparency
            self.status_bar.setStyleSheet(dark)

            style_items(self.all_lists, dark_theme=True)

        # light theme
        elif self.toggle_theme.isChecked() == False:

            palette.setColor(QPalette.Window, QColor(255, 255, 255))
            light = "background-color: rgb(255, 255, 255); color: rgb(0, 0, 0)"

            self.menubar.setStyleSheet(light)
            self.addFields.setStyleSheet(light)
            self.optionMenu.setStyleSheet(light)
            self.fileMenu.setStyleSheet(light)
            self.search_bar.setStyleSheet(light)
            self.status_bar.setStyleSheet(light)

            style_items(self.all_lists, dark_theme=False)

        self.setPalette(palette)

        self.theme_bool = self.toggle_theme.isChecked(
        )  # used in the save func

    def search_item(self):
        """Takes input from the search bar and matches with an item, 
		gets index and scrolls to it, more reusults being qued with the num class var
		"""

        query = self.search_bar.text()
        search = self.all_lists[self.search_col].findItems(
            query, Qt.MatchContains)
        status(self.status_bar, self.list_1, f'Found {len(search)} results.')
        self.clear_selection()

        # testing search in all column

        # search_list =[]
        # for x in range(3):
        # 	search_list.append(self.all_lists[x].findItems(query, Qt.MatchContains))

        # parent_list = []
        # for x in range(3):
        # 	for y in range(len(search_list[x])):
        # 		parent_list.append(self.all_lists[x]) # replace with x

        # import itertools
        # merged = list(itertools.chain.from_iterable(search_list))

        # search_dict = dict(zip(parent_list, merged))
        # print(search_dict)
        # print()
        # print(len(merged))
        # print(len(parent_list))

        self.num += 1
        for i in search:

            try:
                model_index = self.all_lists[self.search_col].indexFromItem(
                    search[self.num])

            except:
                self.num = 0
                model_index = self.all_lists[self.search_col].indexFromItem(
                    search[self.num])

            item_index = model_index.row()

            self.all_lists[self.search_col].item(item_index).setSelected(True)
            self.list_1.scrollToItem(self.list_1.item(item_index),
                                     QAbstractItemView.PositionAtCenter)

    def add_item(self):

        self.show_save = True

        for x in range(3):
            if x == 0:
                lister(file=self.curr_file,
                       target=self.list_1,
                       index=x,
                       mode=1)

            elif x == 1:
                lister(file=self.curr_file,
                       target=self.list_2,
                       index=x,
                       mode=1)

            elif x == 2:
                lister(file=self.curr_file,
                       target=self.list_3,
                       index=x,
                       mode=1)

        item = self.list_1.item(self.list_1.count() - 1)
        self.list_1.editItem(item)
        status(self.status_bar, self.list_1)

        self.list_1.scrollToBottom()
        self.list_2.scrollToBottom()
        self.list_3.scrollToBottom()

    def clear_selection(self):
        """Clears all item slections for aesthetical purposes, but only single clicks"""

        self.list_1.clearSelection()
        self.list_2.clearSelection()
        self.list_3.clearSelection()

    def fileDialog(self):

        fname = QFileDialog()
        path = fname.getOpenFileName(self,
                                     'Open file',
                                     getcwd(),
                                     filter='csv (*.csv);;')
        if path[0] == '':  # failsafe for canceling the dialog
            return self.curr_file

        self.curr_file = path[0]
        self.setWindowTitle(f'{split_name(self.curr_file)}')

        clear_lists(self.all_lists)

        lister(file=self.curr_file, target=self.list_1, index=0)
        lister(file=self.curr_file, target=self.list_2, index=1)
        lister(file=self.curr_file, target=self.list_3, index=2)

        status(self.status_bar, self.list_1)
        self.theme()

    def save(self, mode=0):

        self.show_save = False

        list1_items = items_text(self.list_1)
        list2_items = items_text(self.list_2)
        list3_items = items_text(self.list_3)

        total_dicts = []
        for (a, b, c) in zip(list1_items, list2_items,
                             list3_items):  # each letter is a column
            dictionary = {'word_1': a, 'word_2': b, 'notes': c}
            total_dicts.append(dictionary)

        if mode == 0:

            writer(file=self.curr_file, data=total_dicts)
            status(self.status_bar, self.list_1, ('Saved current changes.'))

            try:
                json_template(theme=self.theme_bool,
                              files=[self.curr_file, None, None],
                              window_size=self.geometry().getRect()
                              )  # current size values of the window

            except:
                json_template(
                )  # bug cannot be avoided, even though used setChecked at the beggining

        elif mode == 1:

            self.show_save = True
            writer(file=self.temp_file, data=total_dicts)

        # avoids stacking and refreshes recent file actions
        actions = self.fileRecents.actions()
        for action in actions:
            self.fileRecents.removeAction(action)
Пример #13
0
class ListUI(QWidget):
    def __init__(self, socman):
        super(ListUI, self).__init__()

        # create objects;

        self.__socman = socman

        self.__ob_list_main = QListWidget()

        self.__ob_line_search = QLineEdit()

        self.__ob_vlay_main = QVBoxLayout()
        self.__ob_hlay_main = QHBoxLayout()

        self.__ob_button_back = Button("Назад")
        self.__ob_button_delete = Button("Удалить", 1)

        self.buttonClicked = 0
        self.doubleClicked = 0

        # config;

        self.setLayout(self.__ob_vlay_main)
        self.setFixedSize(700, 500)

        self.__ob_vlay_main.setSpacing(0)
        self.__ob_vlay_main.addWidget(self.__ob_line_search)
        self.__ob_vlay_main.addWidget(self.__ob_list_main)
        self.__ob_vlay_main.addLayout(self.__ob_hlay_main)
        self.__ob_hlay_main.addWidget(self.__ob_button_back, 4)
        self.__ob_hlay_main.addWidget(self.__ob_button_delete, 1)

        self.__ob_line_search.setStyleSheet("background: rgb(170, 170, 170); border: none;")
        self.__ob_line_search.setFixedHeight(50)
        self.__ob_line_search.textChanged.connect(self.__onLineEdit)

        self.__ob_list_main.setStyleSheet("background: rgb(200, 200, 200); border: none;")
        self.__ob_list_main.setMinimumWidth(self.__ob_list_main.sizeHintForColumn(0))
        self.__ob_list_main.itemDoubleClicked.connect(self.__onDoubleClicked)
        self.__ob_list_main.itemClicked.connect(self.__onItemClicked)
        self.__ob_list_main.setSelectionMode(QListWidget.MultiSelection)

        self.__ob_button_back.clicked.connect(self.__onButtonClicked)
        self.__ob_button_back.setFixedHeight(50)
        self.__ob_button_delete.hide()
        self.__ob_button_delete.clicked.connect(self.__onButtonDeleteClicked)

    def showData(self):
        self.loadList()
        self.show()

    def __onButtonClicked(self):
        self.buttonClicked()

    def __onLineEdit(self):
        self.__ob_button_delete.hide()
        if len(self.__ob_line_search.text()):
            self.__ob_list_main.clear()
            for i in self.__socman.getDump():
                if self.__ob_line_search.text().upper() in i.getTitle().upper():
                    item = QListWidgetItem()
                    item.setText(i.getTitle())
                    item.setSizeHint(QSize(10, 30))
                    self.__ob_list_main.addItem(item)
        else:
            self.loadList()

    def __onDoubleClicked(self, item):
        self.__ob_list_main.clearSelection()
        for i in self.__socman.getDump():
            if item.text() == i.getTitle():
                self.doubleClicked(i)
                break

    def __onItemClicked(self):
        if len(self.__ob_list_main.selectedItems()):
            self.__ob_button_delete.show()
        else:
            self.__ob_button_delete.hide()

    def __onButtonDeleteClicked(self):
        for i in self.__ob_list_main.selectedItems():
            for item in self.__socman.getDump():
                if i.text() == item.getTitle():
                    self.__socman.delete(item)
                    break
        self.__ob_button_delete.hide()
        self.loadList()

    def loadList(self):
        self.__ob_list_main.clear()
        self.__ob_line_search.clear()
        for i in self.__socman.getDump():
            item = QListWidgetItem()
            item.setText(i.getTitle())
            item.setSizeHint(QSize(10, 30))
            self.__ob_list_main.addItem(item)
Пример #14
0
class _HistoryDialog:

    record_label = "Save..."
    execute_label = "Execute"

    def __init__(self, controller, typed_only):
        # make dialog hidden initially
        self.controller = controller
        self.typed_only = typed_only

        self.window = controller.tool_window.create_child_window(
            "Command History", close_destroys=False)
        self.window.fill_context_menu = self.fill_context_menu

        parent = self.window.ui_area
        from PyQt5.QtWidgets import QListWidget, QVBoxLayout, QFrame, QHBoxLayout, QPushButton, QLabel
        self.listbox = QListWidget(parent)
        self.listbox.setSelectionMode(QListWidget.ExtendedSelection)
        self.listbox.itemSelectionChanged.connect(self.select)
        main_layout = QVBoxLayout(parent)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.addWidget(self.listbox)
        num_cmd_frame = QFrame(parent)
        main_layout.addWidget(num_cmd_frame)
        num_cmd_layout = QHBoxLayout(num_cmd_frame)
        num_cmd_layout.setContentsMargins(0, 0, 0, 0)
        remem_label = QLabel("Remember")
        from PyQt5.QtCore import Qt
        remem_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        num_cmd_layout.addWidget(remem_label, 1)
        from PyQt5.QtWidgets import QSpinBox, QSizePolicy

        class ShorterQSpinBox(QSpinBox):
            max_val = 1000000

            def textFromValue(self, val):
                # kludge to make the damn entry field shorter
                if val == self.max_val:
                    return "1 mil"
                return str(val)

        spin_box = ShorterQSpinBox()
        spin_box.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        spin_box.setRange(100, spin_box.max_val)
        spin_box.setSingleStep(100)
        spin_box.setValue(controller.settings.num_remembered)
        spin_box.valueChanged.connect(self._num_remembered_changed)
        num_cmd_layout.addWidget(spin_box, 0)
        num_cmd_layout.addWidget(QLabel("commands"), 1)
        num_cmd_frame.setLayout(num_cmd_layout)
        button_frame = QFrame(parent)
        main_layout.addWidget(button_frame)
        button_layout = QHBoxLayout(button_frame)
        button_layout.setContentsMargins(0, 0, 0, 0)
        for but_name in [
                self.record_label, self.execute_label, "Delete", "Copy", "Help"
        ]:
            but = QPushButton(but_name, button_frame)
            but.setAutoDefault(False)
            but.clicked.connect(
                lambda arg, txt=but_name: self.button_clicked(txt))
            button_layout.addWidget(but)
        button_frame.setLayout(button_layout)
        self.window.manage(placement=None, initially_hidden=True)
        from chimerax.core.history import FIFOHistory
        self._history = FIFOHistory(controller.settings.num_remembered,
                                    controller.session, "commands")
        self._record_dialog = None
        self._search_cache = (False, None)

    def add(self, item, *, typed=False):
        if len(self._history) >= self.controller.settings.num_remembered:
            if not self.typed_only or self._history[0][1]:
                self.listbox.takeItem(0)
        if typed or not self.typed_only:
            self.listbox.addItem(item)
        self._history.enqueue((item, typed))
        # 'if typed:' to avoid clearing any partially entered command text
        if typed:
            self.listbox.clearSelection()
            self.listbox.setCurrentRow(len(self.history()) - 1)
            self.update_list()

    def button_clicked(self, label):
        session = self.controller.session
        if label == self.record_label:
            from chimerax.ui.open_save import SaveDialog
            if self._record_dialog is None:
                fmt = session.data_formats["ChimeraX commands"]
                self._record_dialog = dlg = SaveDialog(session,
                                                       self.window.ui_area,
                                                       "Save Commands",
                                                       data_formats=[fmt])
                from PyQt5.QtWidgets import QFrame, QLabel, QHBoxLayout, QVBoxLayout, QComboBox
                from PyQt5.QtWidgets import QCheckBox
                from PyQt5.QtCore import Qt
                options_frame = dlg.custom_area
                options_layout = QVBoxLayout(options_frame)
                options_frame.setLayout(options_layout)
                amount_frame = QFrame(options_frame)
                options_layout.addWidget(amount_frame, Qt.AlignCenter)
                amount_layout = QHBoxLayout(amount_frame)
                amount_layout.addWidget(QLabel("Save", amount_frame))
                self.save_amount_widget = saw = QComboBox(amount_frame)
                saw.addItems(["all", "selected"])
                amount_layout.addWidget(saw)
                amount_layout.addWidget(QLabel("commands", amount_frame))
                amount_frame.setLayout(amount_layout)
                self.append_checkbox = QCheckBox("Append to file",
                                                 options_frame)
                self.append_checkbox.stateChanged.connect(self.append_changed)
                options_layout.addWidget(self.append_checkbox, Qt.AlignCenter)
                self.overwrite_disclaimer = disclaimer = QLabel(
                    "<small><i>(ignore overwrite warning)</i></small>",
                    options_frame)
                options_layout.addWidget(disclaimer, Qt.AlignCenter)
                disclaimer.hide()
            else:
                dlg = self._record_dialog
            if not dlg.exec():
                return
            path = dlg.selectedFiles()[0]
            if not path:
                from chimerax.core.errors import UserError
                raise UserError("No file specified for saving command history")
            if self.save_amount_widget.currentText() == "all":
                cmds = [cmd for cmd in self.history()]
            else:
                # listbox.selectedItems() may not be in order, so...
                items = [
                    self.listbox.item(i) for i in range(self.listbox.count())
                    if self.listbox.item(i).isSelected()
                ]
                cmds = [item.text() for item in items]
            from chimerax.io import open_output
            f = open_output(path,
                            encoding='utf-8',
                            append=self.append_checkbox.isChecked())
            for cmd in cmds:
                print(cmd, file=f)
            f.close()
            return
        if label == self.execute_label:
            for item in self.listbox.selectedItems():
                self.controller.cmd_replace(item.text())
                self.controller.execute()
            return
        if label == "Delete":
            retain = []
            listbox_index = 0
            for h_item in self._history:
                if self.typed_only and not h_item[1]:
                    retain.append(h_item)
                    continue
                if not self.listbox.item(listbox_index).isSelected():
                    # not selected for deletion
                    retain.append(h_item)
                listbox_index += 1
            self._history.replace(retain)
            self.populate()
            return
        if label == "Copy":
            clipboard = session.ui.clipboard()
            clipboard.setText("\n".join(
                [item.text() for item in self.listbox.selectedItems()]))
            return
        if label == "Help":
            from chimerax.core.commands import run
            run(session, 'help help:user/tools/cli.html#history')
            return

    def down(self, shifted):
        sels = self.listbox.selectedIndexes()
        if len(sels) != 1:
            self._search_cache = (False, None)
            return
        sel = sels[0].row()
        orig_text = self.controller.text.currentText()
        match_against = None
        if shifted:
            was_searching, prev_search = self._search_cache
            if was_searching:
                match_against = prev_search
            else:
                words = orig_text.strip().split()
                if words:
                    match_against = words[0]
                    self._search_cache = (True, match_against)
                else:
                    self._search_cache = (False, None)
        else:
            self._search_cache = (False, None)
        if match_against:
            last = self.listbox.count() - 1
            while sel < last:
                if self.listbox.item(sel + 1).text().startswith(match_against):
                    break
                sel += 1
        if sel == self.listbox.count() - 1:
            return
        self.listbox.clearSelection()
        self.listbox.setCurrentRow(sel + 1)
        new_text = self.listbox.item(sel + 1).text()
        self.controller.cmd_replace(new_text)
        if orig_text == new_text:
            self.down(shifted)

    def fill_context_menu(self, menu, x, y):
        # avoid having actions destroyed when this routine returns
        # by stowing a reference in the menu itself
        from PyQt5.QtWidgets import QAction
        filter_action = QAction("Typed commands only", menu)
        filter_action.setCheckable(True)
        filter_action.setChecked(self.controller.settings.typed_only)
        filter_action.toggled.connect(
            lambda arg, f=self.controller._set_typed_only: f(arg))
        menu.addAction(filter_action)

    def on_append_change(self, event):
        self.overwrite_disclaimer.Show(self.save_append_CheckBox.Value)

    def append_changed(self, append):
        if append:
            self.overwrite_disclaimer.show()
        else:
            self.overwrite_disclaimer.hide()

    def on_listbox(self, event):
        self.select()

    def populate(self):
        self.listbox.clear()
        history = self.history()
        self.listbox.addItems([cmd for cmd in history])
        self.listbox.setCurrentRow(len(history) - 1)
        self.update_list()
        self.select()
        self.controller.text.lineEdit().setFocus()
        self.controller.text.lineEdit().selectAll()
        cursels = self.listbox.scrollToBottom()

    def search_reset(self):
        searching, target = self._search_cache
        if searching:
            self._search_cache = (False, None)
            self.listbox.blockSignals(True)
            self.listbox.clearSelection()
            self.listbox.setCurrentRow(self.listbox.count() - 1)
            self.listbox.blockSignals(False)

    def select(self):
        sels = self.listbox.selectedItems()
        if len(sels) != 1:
            return
        self.controller.cmd_replace(sels[0].text())

    def up(self, shifted):
        sels = self.listbox.selectedIndexes()
        if len(sels) != 1:
            self._search_cache = (False, None)
            return
        sel = sels[0].row()
        orig_text = self.controller.text.currentText()
        match_against = None
        if shifted:
            was_searching, prev_search = self._search_cache
            if was_searching:
                match_against = prev_search
            else:
                words = orig_text.strip().split()
                if words:
                    match_against = words[0]
                    self._search_cache = (True, match_against)
                else:
                    self._search_cache = (False, None)
        else:
            self._search_cache = (False, None)
        if match_against:
            while sel > 0:
                if self.listbox.item(sel - 1).text().startswith(match_against):
                    break
                sel -= 1
        if sel == 0:
            return
        self.listbox.clearSelection()
        self.listbox.setCurrentRow(sel - 1)
        new_text = self.listbox.item(sel - 1).text()
        self.controller.cmd_replace(new_text)
        if orig_text == new_text:
            self.up(shifted)

    def update_list(self):
        c = self.controller
        last8 = list(reversed(self.history()[-8:]))
        # without blocking signals, if the command list is empty then
        # "Command History" (the first entry) will execute...
        c.text.blockSignals(True)
        c.text.clear()
        c.text.addItems(last8 + [c.show_history_label, c.compact_label])
        if not last8:
            c.text.lineEdit().setText("")
        c.text.blockSignals(False)

    def history(self):
        if self.typed_only:
            return [h[0] for h in self._history if h[1]]
        return [h[0] for h in self._history]

    def set_typed_only(self, typed_only):
        self.typed_only = typed_only
        self.populate()

    def _num_remembered_changed(self, new_hist_len):
        if len(self._history) > new_hist_len:
            self._history.replace(self._history[-new_hist_len:])
            self.populate()
        self.controller.settings.num_remembered = new_hist_len
Пример #15
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        self.item_cnt = 0
        #TODO
        self.setcolor = QColor(0, 0, 0)

        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(600, 600)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget

        # 设置菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')
        set_pen_act = file_menu.addAction('设置画笔')
        reset_canvas_act = file_menu.addAction('重置画布')
        exit_act = file_menu.addAction('退出')
        draw_menu = menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        edit_menu = menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')

        # 连接信号和槽函数
        exit_act.triggered.connect(qApp.quit)
        line_naive_act.triggered.connect(self.line_naive_action)
        #TODO
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)
        set_pen_act.triggered.connect(self.set_pen_action)
        reset_canvas_act.triggered.connect(self.reset_canvas_action)
        ellipse_act.triggered.connect(self.ellipse_action)
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)
        clip_cohen_sutherland_act.triggered.connect(self.clip_cohen_sutherland_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)
        self.list_widget.currentTextChanged.connect(self.canvas_widget.selection_changed)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(600, 600)
        self.setWindowTitle('CG Demo')

    def get_id(self):
        _id = str(self.item_cnt)
        self.item_cnt += 1
        return _id

    def line_naive_action(self):
        self.canvas_widget.start_draw_line('Naive', self.get_id())
        self.statusBar().showMessage('Naive算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
    
    #TODO
    def line_dda_action(self):
        self.canvas_widget.start_draw_line('DDA', self.get_id())
        self.statusBar().showMessage('DDA算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        self.canvas_widget.start_draw_line('Bresenham', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
    
    def polygon_dda_action(self):
        self.canvas_widget.start_draw_polygon('DDA', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制polygon')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
    
    def polygon_bresenham_action(self):
        self.canvas_widget.start_draw_polygon('Bresenham', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制polygon')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def set_pen_action(self):
        color = QColorDialog.getColor()
        self.setcolor = color
        self.statusBar().showMessage('设置画笔')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def reset_canvas_action(self):
        self.item_cnt = 0
        dialog = QDialog()
        dialog.setWindowTitle('重置画布')
        dialog.resize(400,247)
        height, width = 0, 0
        errorFlag = 0
        while 1:
            if ((height < 100 or width < 100 or height > 1000 or width > 1000) and (errorFlag == 0)):
                height, heightPressed = QInputDialog.getInt(self, '重置画布', 'Please input height(range:100-1000):', QLineEdit.Normal)
                width, widthPressed = QInputDialog.getInt(self, '重置画布', 'Please input width(range:100-1000):', QLineEdit.Normal)
                errorFlag = 1
            elif ((height < 100 or width < 100 or height > 1000 or width > 1000) and (errorFlag == 1)):
                QMessageBox.critical(self, 'Error', 'out of range')
                errorFlag = 0
            else:
                break

        if heightPressed and height and widthPressed and width:
            #clear item
            self.canvas_widget.clearItem()
            self.list_widget.clearSelection()
            self.canvas_widget.clear_selection()
            #resetsize
            self.scene = QGraphicsScene(self)
            self.scene.setSceneRect(0, 0, width, height)
            self.canvas_widget.resize(width, height)
            self.canvas_widget.setFixedSize(width, height)
            self.statusBar().showMessage('空闲')
            self.setMaximumSize(width, height)
            self.resize(width, height)

    def ellipse_action(self):
        self.canvas_widget.start_draw_ellipse(self.get_id())
        self.statusBar().showMessage('椭圆')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        self.canvas_widget.start_draw_curve('Bezier', self.get_id(), 3)#numofpoint
        self.statusBar().showMessage('Bezier算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        self.canvas_widget.start_draw_curve('B-spline', self.get_id(), 4)#numofpoint
        self.statusBar().showMessage('B-spline算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def translate_action(self):
        self.canvas_widget.start_translate()
        self.statusBar().showMessage('平移')
        #self.list_widget.clearSelection()
        #self.canvas_widget.clear_selection()

    def rotate_action(self):
        self.canvas_widget.start_rotate()
        self.statusBar().showMessage('旋转')
        #self.list_widget.clearSelection()
        #self.canvas_widget.clear_selection()
    
    def scale_action(self):
        self.canvas_widget.start_scale()
        self.statusBar().showMessage('缩放')
        #self.list_widget.clearSelection()
        #self.canvas_widget.clear_selection()

    def clip_cohen_sutherland_action(self):
        self.canvas_widget.start_clip('Cohen-Sutherland')
        self.statusBar().showMessage('Cohen-Sutherland算法裁剪')
        #self.list_widget.clearSelection()
        #self.canvas_widget.clear_selection()

    def clip_liang_barsky_action(self):
        self.canvas_widget.start_clip('Liang-Barsky')
        self.statusBar().showMessage('Liang-Barsky算法裁剪')
Пример #16
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        self.item_cnt = 0

        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(600, 600)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget

        #confirm button
        self.btn = QPushButton('OK', self)
        self.btn.setFixedSize(40, 30)
        
        # 设置菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')
        set_pen_act = file_menu.addAction('设置画笔')
        reset_canvas_act = file_menu.addAction('重置画布')
        save_canvas_act = file_menu.addAction('保存画布')
        exit_act = file_menu.addAction('退出')
        draw_menu = menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        edit_menu = menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')
        addition_func_menu = menubar.addMenu('附加功能')
        select_item_act = addition_func_menu.addAction('选择图元')
        polygon_addition_menu = addition_func_menu.addMenu('多边形')
        polygon_fill_act = polygon_addition_menu.addAction('多边形填充')
        polygon_clip_act = polygon_addition_menu.addAction('多边形裁剪')
        copy_act = addition_func_menu.addAction('复制粘贴')
        undo_act = addition_func_menu.addAction('撤销')
        delete_act = addition_func_menu.addAction('删除')
        
        # 连接信号和槽函数
        exit_act.triggered.connect(qApp.quit)
        set_pen_act.triggered.connect(self.set_pen_action)
        reset_canvas_act.triggered.connect(self.reset_canvas_action)
        save_canvas_act.triggered.connect(self.save_canvas_action)
        line_naive_act.triggered.connect(self.line_naive_action)
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)
        ellipse_act.triggered.connect(self.ellipse_action)
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)
        clip_cohen_sutherland_act.triggered.connect(self.clip_cohen_sutherland_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)
        self.list_widget.currentTextChanged.connect(self.canvas_widget.selection_changed)
        self.btn.clicked.connect(self.on_click)
        select_item_act.triggered.connect(self.select_item_action)
        polygon_fill_act.triggered.connect(self.polygon_fill_action)
        polygon_clip_act.triggered.connect(self.polygon_clip_action)
        copy_act.triggered.connect(self.copy_action)
        undo_act.triggered.connect(self.undo_action)
        delete_act.triggered.connect(self.delete_action)
        
        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        #TODO: move button to down below
        self.hbox_layout.addWidget(self.btn)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(600, 600)
        self.setWindowTitle('CG Demo')

    def reset_id(self):
        self.item_cnt = 0
        
    def get_id(self):
        self.item_cnt += 1
        _id = str(self.item_cnt)
        return _id
    
    def get_present_id(self):
        _id = str(self.item_cnt)
        return _id 
        
    def set_pen_action(self):
        col = QColorDialog.getColor()
        if col.isValid():
            self.canvas_widget.start_change_color(col)
     
    def reset_canvas_action(self):
        self.canvas_widget.start_reset_canvas()
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        
        dialog = QDialog()
        form = QFormLayout(dialog)
        box1 = QSpinBox(dialog)
        box1.setRange(100, 1000)
        box2 = QSpinBox(dialog)
        box2.setRange(100, 1000)
        form.addRow('Width:', box1)
        form.addRow('Height:', box2)
        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.rejected.connect(dialog.reject)
        form.addRow(buttonBox)
        
        if dialog.exec():
            self.w = box1.value()
            self.h = box2.value()
            self.scene.setSceneRect(0, 0, self.w, self.h)
            self.canvas_widget.resize(self.w,self.h)
            self.canvas_widget.setFixedSize(self.w, self.h)
            self.statusBar().showMessage('空闲')
            self.setMaximumHeight(self.h)
            self.setMaximumWidth(self.w)
            self.resize(self.w, self.h)
    
    def save_canvas_action(self):
        self.canvas_widget.start_save_canvas()
    
    def line_naive_action(self):
        self.canvas_widget.start_draw_line('Naive', self.get_present_id())
        self.statusBar().showMessage('Naive算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_dda_action(self):
        self.canvas_widget.start_draw_line('DDA', self.get_present_id())
        self.statusBar().showMessage('DDA算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
    
    def line_bresenham_action(self):
        self.canvas_widget.start_draw_line('Bresenham', self.get_present_id())
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        
    def polygon_dda_action(self):
        self.canvas_widget.start_draw_polygon('DDA', self.get_present_id())
        self.statusBar().showMessage('DDA算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        
    def polygon_bresenham_action(self):
        self.canvas_widget.start_draw_polygon('Bresenham', self.get_present_id())
        self.statusBar().showMessage('Bresenham算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        
    def ellipse_action(self):
        self.canvas_widget.start_draw_ellipse(self.get_present_id())
        self.statusBar().showMessage('绘制椭圆')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        self.canvas_widget.start_draw_curve('Bezier', self.get_present_id())
        self.statusBar().showMessage('Bezier算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
    
    def curve_b_spline_action(self):
        self.canvas_widget.start_draw_curve('B-spline', self.get_present_id())
        self.statusBar().showMessage('B-spline算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
    
    def translate_action(self):
        self.canvas_widget.start_translate()
        self.statusBar().showMessage('图元平移')
        
    def rotate_action(self):
        self.canvas_widget.start_rotate()
        self.statusBar().showMessage('图元旋转')

    def scale_action(self):
        self.canvas_widget.start_scale()
        self.statusBar().showMessage('图元缩放')
        
    def clip_cohen_sutherland_action(self):
        self.canvas_widget.start_clip('Cohen-Sutherland')
        self.statusBar().showMessage('Cohen-Sutherland算法对线段裁剪')
        
    def clip_liang_barsky_action(self):
        self.canvas_widget.start_clip('Liang-Barsky')
        self.statusBar().showMessage('Liang-Barsky算法对线段裁剪') 
        
    def on_click(self):
        self.canvas_widget.finish_draw_curve(self.get_present_id())
        
    def select_item_action(self):
        self.canvas_widget.select_item()
        self.statusBar().showMessage('鼠标点击选择图元')
        
    def polygon_fill_action(self):
        self.canvas_widget.start_polygon_fill()
        self.statusBar().showMessage('多边形填充')
        
    def polygon_clip_action(self):
        self.canvas_widget.start_polygon_clip()
        self.statusBar().showMessage('多边形裁剪')
    
    def copy_action(self):
        self.canvas_widget.start_copy()
        self.statusBar().showMessage('图元复制粘贴')
        
    def undo_action(self):
        self.canvas_widget.start_undo()
        self.statusBar().showMessage('撤销操作')
        
    def delete_action(self):
        self.canvas_widget.start_delete()
        self.statusBar().showMessage('删除图元')
Пример #17
0
class ArtToolWindow(QMainWindow):

    # --------------------------------------------------
    # CONSTRUCTOR
    # --------------------------------------------------
    def __init__(self, *args):
        super(ArtToolWindow, self).__init__(*args)

        # State
        self.metadata = None
        self.comboTabIdx = -1
        self.currentFbx = -1
        self.currentCombo = -1
        self.ignoreSVN = 0
        self.additionsClipboard = None
        self.cancelledSVN = False
        self.editPane = None
        self.currentFilter = None
        self.lastSVNCheck = 0
        self.dialogUp = False
        self.mainLayout = None

        # Load our config
        self.config = createGetConfig()

        # Left Pane
        leftPane = QWidget()
        leftLayout = QVBoxLayout(leftPane)

        # Streamlabs logo
        slabslogo = QLabel()
        slabslogo.setPixmap(QPixmap("arttool/streamlabs.png"))
        slabslogo.setScaledContents(True)
        slabslogo.show()
        leftLayout.addWidget(slabslogo)
        slabslogo.setMaximumWidth(300)
        slabslogo.setMaximumHeight(53)

        # Filter box
        self.fbxfilter = QLineEdit()
        self.fbxfilter.editingFinished.connect(lambda: self.onFbxFilterChanged())
        leftLayout.addWidget(self.fbxfilter)

        # make a list widget for fbx's
        self.fbxlist = QListWidget()
        self.fbxlist.itemSelectionChanged.connect(lambda: self.onFbxClicked())
        self.fbxlist.setMinimumHeight(640)

        # make the combo tab
        combotab = QWidget()
        combotab.setAutoFillBackground(True)

        # combo buttons
        b = QPushButton("Add")
        b.setParent(combotab)
        b.setGeometry(5,5, 75, 30)
        b.pressed.connect(lambda: self.onAddCombo())
        b = QPushButton("Del")
        b.setParent(combotab)
        b.setGeometry(85, 5, 75, 30)
        b.pressed.connect(lambda: self.onDelCombo())

        # make alist widget for combos
        self.combolist = QListWidget()
        self.combolist.itemSelectionChanged.connect(lambda: self.onComboClicked())
        self.combolist.setParent(combotab)
        self.combolist.setGeometry(0, 40, 294, 600)

        # make fbx/combo tabs
        tabs = QTabWidget()
        tabs.currentChanged.connect(lambda i: self.onComboTabChanged(i))
        tabs.setGeometry(0,0,300, 640)
        tabs.addTab(self.fbxlist, "FBX")
        tabs.addTab(combotab, "COMBOS")

        leftLayout.addWidget(tabs)

        # top splitter
        topSplitter = QSplitter(Qt.Horizontal)
        topSplitter.addWidget(leftPane)

        # Layout for edit pane
        rightPane = QWidget()
        self.mainLayout = QHBoxLayout(rightPane)
        topSplitter.addWidget(rightPane)

        # Fill in files lists
        self.fillFbxList()
        self.fillComboList()

        # crate main splitter
        mainSplitter = QSplitter(Qt.Vertical)
        mainSplitter.addWidget(topSplitter)

        # bottom pane
        bottomPane = QWidget()
        bottomArea = QHBoxLayout(bottomPane)

        # output window
        self.outputWindow = QTextEdit()
        self.outputWindow.setMinimumHeight(90)
        bottomArea.addWidget(self.outputWindow)

        # buttons area
        buttonArea = QWidget()
        buttonArea.setMinimumWidth(150)
        buttonArea.setMinimumHeight(60)
        locs = [(0, 0), (0, 30), (0, 60), (75, 0), (75, 30), (75, 60)]
        c = 0
        for nn in ["Refresh", "Autobuild", "Rebuild All", "S3 Upload", "XLS Export", "Release Masks"]:
            b = QPushButton(nn)
            b.setParent(buttonArea)
            (x, y) = locs[c]
            c += 1
            b.setGeometry(x, y, 75, 30)
            b.pressed.connect(lambda nn=nn: self.onMainButton(nn))
        bottomArea.addWidget(buttonArea)

        mainSplitter.addWidget(bottomPane)

        # Show the window
        self.setCentralWidget(mainSplitter)
        self.setGeometry(self.config["x"], self.config["y"], 1024, 900)
        self.setWindowTitle('Streamlabs Art Tool')
        self.setWindowIcon(QIcon('arttool/arttoolicon.png'))

        # Check our binaries
        self.checkBinaries()

    # --------------------------------------------------
    # Fill(refill) in the fbx list
    # --------------------------------------------------
    def fillFbxList(self):
        # Get list of fbx files
        self.fbxfiles = getFbxFileList(".")

        # Clear list
        while self.fbxlist.count() > 0:
            i = self.fbxlist.takeItem(0)
            i = None

        # Get filter
        filt = self.fbxfilter.text().lower()
        if not filt or len(filt) < 1:
            filt = None

        # Fill list
        self.fbxlistMap = dict()
        self.fbxlistRevMap = dict()
        fbxidx = 0
        listidx = 0
        for fbx in self.fbxfiles:
            if not filt or filt in fbx.lower():
                self.fbxlist.addItem(fbx[2:])
                self.fbxlistMap[listidx] = fbxidx
                self.fbxlistRevMap[fbxidx] = listidx
                listidx += 1
            fbxidx += 1

        # color fbxlist items
        for idx in range(0, len(self.fbxfiles)):
            self.setFbxColorIcon(idx)

        self.resetEditPane()


    # --------------------------------------------------
    # Fill(refill) in the combos list
    # --------------------------------------------------
    def fillComboList(self):
        # Get list of fbx files
        self.combofiles = getComboFileList(".")

        # Clear list
        while self.combolist.count() > 0:
            i = self.combolist.takeItem(0)
            i = None

        # Fill list
        for combo in self.combofiles:
            self.combolist.addItem(combo[2:])
            idx = self.combolist.count() - 1

        # color list items
        for idx in range(0, len(self.combofiles)):
            self.setComboColorIcon(idx)

        self.resetEditPane()


    def resetEditPane(self):
        self.currentCombo = -1
        self.currentFbx = -1
        self.metadata = None
        self.fbxlist.clearSelection()
        self.combolist.clearSelection()
        if self.mainLayout is not None:
            self.createMaskEditPane(None)

    # --------------------------------------------------
    # Check binaries
    # --------------------------------------------------
    def checkBinaries(self):
        gotSVN = os.path.exists(SVNBIN.replace('"', ''))
        gotMM = os.path.exists(MASKMAKERBIN)
        gotRP = os.path.exists(MORPHRESTFILE)

        if not gotSVN:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            msg.setText("You seem to be missing " + os.path.basename(SVNBIN))
            msg.setInformativeText("You should (re)install tortoiseSVN, and be sure to install the command line tools.")
            msg.setWindowTitle("Missing Binary File")
            msg.setStandardButtons(QMessageBox.Ok)
            self.ignoreSVN += 1
            self.dialogUp = True
            msg.exec_()
            self.dialogUp = False
        if not gotMM:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            msg.setText("You seem to be missing " + os.path.basename(MASKMAKERBIN))
            msg.setWindowTitle("Missing Binary File")
            msg.setStandardButtons(QMessageBox.Ok)
            self.ignoreSVN += 1
            self.dialogUp = True
            msg.exec_()
            self.dialogUp = False
        if not gotRP:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            msg.setText("You seem to be missing " + os.path.basename(MORPHRESTFILE))
            msg.setWindowTitle("Missing Binary File")
            msg.setStandardButtons(QMessageBox.Ok)
            self.ignoreSVN += 1
            self.dialogUp = True
            msg.exec_()
            self.dialogUp = False

    # --------------------------------------------------
    # Create generic widget
    # --------------------------------------------------
    def createLabelWidget(self, parent, name, field, x, y, noedit=False):
        q = QLabel(name)
        q.setParent(parent)
        q.setGeometry(x, y, FIELD_WIDTH - 10, 26)
        q.setFont(QFont("Arial", 12, QFont.Bold))
        q.show()

        if field == None:
            return q

        critical = critical_mask
        if self.metadata["fbx"].lower().endswith(".json"):
            critical = critical_combo

        value = self.metadata[field]

        if field in DROP_DOWNS:
            dropvals = DROP_DOWNS[field]
            q = QComboBox()
            idx = 0
            selidx = -1
            for s in dropvals:
                if s == str(value):
                    selidx = idx
                q.addItem(s)
                idx += 1
            if selidx < 0:
                selidx = 0

            q.setCurrentIndex(selidx)
            q.currentIndexChanged.connect(lambda state: self.onDropdownChanged(state, field))
        elif type(value) is str or type(value) is float or type(value) is int:
            if noedit:
                q = QLabel(str(value))
            else:
                q = QLineEdit(str(value))
                q.textChanged.connect(lambda text: self.onTextFieldChanged(text, field))
            if critical(field) and len(value) == 0:
                q.setStyleSheet("border: 1px solid #FF0000;")
            elif desired(field) and len(value) == 0:
                q.setStyleSheet("border: 1px solid #FF7F50;")
            else:
                q.setStyleSheet("border: 0px;")
        elif type(value) is bool:
            q = QCheckBox()
            q.setChecked(value)
            q.stateChanged.connect(lambda state: self.onCheckboxChanged(state, field))

        q.setParent(parent)
        if type(value) is int:
            q.setGeometry(x + FIELD_WIDTH - 10, y, FIELD_WIDTH, 20)
        else:
            q.setGeometry(x + FIELD_WIDTH - 10, y, PANE_WIDTH - FIELD_WIDTH - 10, 20)
        q.setFont(QFont("Arial", 12, QFont.Bold))
        q.show()
        return q

    # --------------------------------------------------
    # Colors and Icons for main FBX list
    # --------------------------------------------------
    def setFbxColorIconInternal(self, mdc, mt, nb, idx):
        self.fbxlist.item(idx).setFont(QFont("Arial", 12, QFont.Bold))
        if mdc == CHECKMETA_GOOD:
            self.fbxlist.item(idx).setForeground(QBrush(QColor("#32CD32")))
        elif mdc == CHECKMETA_ERROR:
            self.fbxlist.item(idx).setForeground(QBrush(QColor("#FF0000")))
        elif mdc == CHECKMETA_WARNING:
            self.fbxlist.item(idx).setForeground(QBrush(QColor("#FF7F50")))
        elif mdc == CHECKMETA_NORELEASE:
            self.fbxlist.item(idx).setForeground(QBrush(QColor("#000000")))
        elif mdc == CHECKMETA_WITHPLUGIN:
            self.fbxlist.item(idx).setForeground(QBrush(QColor("#5070FF")))
        if mt == MASK_UNKNOWN:
            self.fbxlist.item(idx).setIcon(QIcon("arttool/unknownicon.png"))
        else:
            if nb:
                if mt == MASK_NORMAL:
                    self.fbxlist.item(idx).setIcon(QIcon("arttool/maskicon_build.png"))
                elif mt == MASK_MORPH:
                    self.fbxlist.item(idx).setIcon(QIcon("arttool/morphicon_build.png"))
            else:
                if mt == MASK_NORMAL:
                    self.fbxlist.item(idx).setIcon(QIcon("arttool/maskicon.png"))
                elif mt == MASK_MORPH:
                    self.fbxlist.item(idx).setIcon(QIcon("arttool/morphicon.png"))

    def setFbxColorIcon(self, idx):
        if idx in self.fbxlistRevMap:
            mdc, mt = checkMetaDataFile(self.fbxfiles[idx])
            nb = doesFileNeedRebuilding(self.fbxfiles[idx])
            self.setFbxColorIconInternal(mdc, mt, nb, self.fbxlistRevMap[idx])

    def setComboColorIconInternal(self, mdc, mt, nb, idx):
        self.combolist.item(idx).setFont(QFont("Arial", 12, QFont.Bold))
        if mdc == CHECKMETA_GOOD:
            self.combolist.item(idx).setForeground(QBrush(QColor("#32CD32")))
        elif mdc == CHECKMETA_ERROR:
            self.combolist.item(idx).setForeground(QBrush(QColor("#FF0000")))
        elif mdc == CHECKMETA_WARNING:
            self.combolist.item(idx).setForeground(QBrush(QColor("#FF7F50")))
        elif mdc == CHECKMETA_NORELEASE:
            self.combolist.item(idx).setForeground(QBrush(QColor("#000000")))
        elif mdc == CHECKMETA_WITHPLUGIN:
            self.combolist.item(idx).setForeground(QBrush(QColor("#5070FF")))
        if nb:
            self.combolist.item(idx).setIcon(QIcon("arttool/comboicon_build.png"))
        else:
            self.combolist.item(idx).setIcon(QIcon("arttool/comboicon.png"))

    def setComboColorIcon(self, idx):
        mdc, mt = checkMetaDataFile(self.combofiles[idx])
        nb = doesFileNeedRebuilding(self.combofiles[idx])
        self.setComboColorIconInternal(mdc, mt, nb, idx)


    def updateListColorIcon(self):
        mdc, mt = checkMetaData(self.metadata)
        nb = doesFileNeedRebuilding(self.metadata["fbx"], self.metadata)
        if self.comboTabIdx == 0:
            self.setFbxColorIconInternal(mdc, mt, nb, self.fbxlistRevMap[self.currentFbx])
        else:
            self.setComboColorIconInternal(mdc, mt, nb, self.currentCombo)



    # --------------------------------------------------
    # createMaskEditPane
    # --------------------------------------------------
    def createMaskEditPane(self, fbxfile):
        if self.editPane:
            self.mainLayout.removeWidget(self.editPane)
            self.editPane.deleteLater()

        self.editPane = QWidget()
        self.mainLayout.addWidget(self.editPane)
        self.editPane.setMinimumWidth(PANE_WIDTH)
        self.editPane.show()

        # empty pane
        if fbxfile == None:
            return

        # mask icon png
        q = QLabel()
        q.setParent(self.editPane)
        pf = os.path.abspath(fbxfile.lower().replace(".fbx", ".gif").replace(".json", ".gif"))
        if os.path.exists(pf):
            m = QMovie(pf)
        else:
            m = QMovie("arttool/noicon.png")
        q.setMovie(m)
        m.start()
        q.setScaledContents(True)
        q.setGeometry(0, 2, 256, 256)
        q.show()

        # mask file name
        q = QLabel(fbxfile[2:])
        q.setParent(self.editPane)
        q.setGeometry(260, 44, 600, 36)
        q.setFont(QFont("Arial", 14, QFont.Bold))
        q.show()

        # uuid
        q = QLabel(self.metadata["uuid"])
        q.setParent(self.editPane)
        q.setGeometry(260, 80, 600, 20)
        q.setStyleSheet("font: 10pt;")
        # q.setFont(QFont( "Arial", 6))
        q.show()

        # buttons
        b = QPushButton("BUILD")
        b.setParent(self.editPane)
        b.setGeometry(260, 2, 64, 32)
        q.setFont(QFont("Arial", 14, QFont.Bold))
        b.pressed.connect(lambda: self.onBuild())
        b.show()

        # Tabbed Panel
        tabs = QTabWidget(self.editPane)
        tabs.setGeometry(0, 264, PANE_WIDTH, 600)

        # mask meta data fields
        tab1 = QWidget()
        y = 2
        dy = 28
        self.paneWidgets = dict()
        for field in UI_FIELDS[self.comboTabIdx]:
            if field != "uuid":
                w = self.createLabelWidget(tab1, MASK_UI_NAMES[field], field, 10, y)
                self.paneWidgets[field] = w
                if field in MASK_FIELD_TOOLTIPS:
                    w.setToolTip(MASK_FIELD_TOOLTIPS[field])
                y += dy
        tab1.setAutoFillBackground(True)
        tabs.addTab(tab1, "Mask Meta Data")

        if self.comboTabIdx == 0:
            tab2 = self.createAdditionsTab()
            tabs.addTab(tab2, "Additions")
        else:
            tab2 = self.createCombosTab()
            tabs.addTab(tab2, "Combinations")

        tabs.show()


    def createCombosTab(self):
        # combos tab
        tab2 = QWidget()
        y = 10
        dy = 40
        self.createLabelWidget(tab2, "Combo Files", None, 10, y)
        y += dy

        self.comboWidgets = list()

        for cidx in range(0,10):
            q = QComboBox()
            idx = 1
            selidx = -1
            value = self.metadata["additions"][cidx]
            q.addItem(" None ")
            for f in self.fbxfiles:
                if f == str(value):
                    selidx = idx
                q.addItem(f[2:])
                idx += 1
            if selidx < 0:
                selidx = 0
            q.setCurrentIndex(selidx)
            q.setParent(tab2)
            q.setGeometry(10, y, 600, 30)
            y += dy
            q.setFont(QFont("Arial", 12, QFont.Bold))
            q.show()
            q.currentIndexChanged.connect(lambda state, cidx=cidx: self.onComboFileChanged(state,cidx))
            self.comboWidgets.append(q)

        tab2.setAutoFillBackground(True)
        return tab2


    def createAdditionsTab(self):
        # additions tab
        tab2 = QWidget()
        y = 10
        dy = 40
        self.createLabelWidget(tab2, "Mask Build Additions", None, 10, y)
        y += dy

        # make a list widget
        self.addslist = QListWidget()
        if "additions" in self.metadata:
            additions = self.metadata["additions"]
            idx = 0
            for addition in additions:
                self.addslist.addItem(addition["type"] + " : " + addition["name"])
                self.addslist.item(idx).setFont(QFont("Arial", 12, QFont.Bold))
                idx += 1
        self.addslist.itemDoubleClicked.connect(lambda: self.onEditAddition())
        self.addslist.setParent(tab2)
        self.addslist.setGeometry(10, y, PANE_WIDTH - 20, 250)
        y += 260

        # bottom buttons for additons
        x = 10
        b = QPushButton("Add")
        b.setParent(tab2)
        b.setGeometry(x, y, 75, 30)
        b.pressed.connect(lambda: self.onAddAddition())
        x += 85
        b = QPushButton("Edit")
        b.setParent(tab2)
        b.setGeometry(x, y, 75, 30)
        b.pressed.connect(lambda: self.onEditAddition())
        x += 85
        b = QPushButton("Del")
        b.setParent(tab2)
        b.setGeometry(x, y, 75, 30)
        b.pressed.connect(lambda: self.onDelAddition())
        x += 85
        b = QPushButton("Dupe")
        b.setParent(tab2)
        b.setGeometry(x, y, 75, 30)
        b.pressed.connect(lambda: self.onCopyAddition())
        x += 85
        b = QPushButton("Up")
        b.setParent(tab2)
        b.setGeometry(x, y, 75, 30)
        b.pressed.connect(lambda: self.onMoveUpAddition())
        x += 85
        b = QPushButton("Down")
        b.setParent(tab2)
        b.setGeometry(x, y, 75, 30)
        b.pressed.connect(lambda: self.onMoveDownAddition())

        # top buttons for additions
        x = 300
        b = QPushButton("COPY ALL")
        b.setParent(tab2)
        b.setGeometry(x, 10, 75, 30)
        b.pressed.connect(lambda: self.onCopyAllAdditions())
        x += 85
        b = QPushButton("PASTE ALL")
        b.setParent(tab2)
        b.setGeometry(x, 10, 75, 30)
        b.pressed.connect(lambda: self.onPasteAllAdditions())

        tab2.setAutoFillBackground(True)
        return tab2


    # --------------------------------------------------
    # saveCurrentMetadata
    # --------------------------------------------------
    def saveCurrentMetadata(self):
        if self.metadata:
            fbxfile = None
            if self.currentFbx >= 0:
                fbxfile = self.fbxfiles[self.currentFbx]
            elif self.currentCombo >= 0:
                fbxfile = self.combofiles[self.currentCombo]

            if fbxfile:
                metafile = getMetaFileName(fbxfile)
                oldmetadata = loadMetadataFile(fbxfile)
                if oldmetadata != self.metadata:
                    writeMetaData(metafile, self.metadata, True)
                    print("saving", metafile)

    # --------------------------------------------------
    # WIDGET SIGNALS CALLBACKS
    # --------------------------------------------------

    # Main buttons
    def onMainButton(self, button):
        if button == "S3 Upload":
            self.uploadToS3()
        elif button == "Refresh":
            self.fillFbxList()
            self.fillComboList()
        elif button == "Autobuild":
            self.doAutobuild()
        elif button == "Rebuild All":
            self.doRebuildAll()
        elif button == "XLS Export":
            self.onWriteMetadataExcel()
        elif button == "Release Masks":
            self.doReleaseMasks()

    # TODO : hook up to a button
    def onMakeThumbsMovie(self):
        # self.ignoreSVN += 1
        # self.dialogUp = True
        # addn = ReleasesDialog.go_modal(self)
        # self.dialogUp = False

        # quick hack for fun
        framenum = 1
        for fbx in self.fbxfiles:
            src = os.path.abspath(fbx.replace(".fbx", ".png").replace(".FBX", ".png"))
            # dst = "c:\\Temp\\masks\\frame%04d.png" % framenum
            dst = "c:\\Temp\\masks\\" + os.path.basename(src)

            fileOkay = True
            if "frogHead" in src:
                fileOkay = False
            if "joshog" in src:
                fileOkay = False

            if os.path.exists(src) and fileOkay:
                print("copy", src, dst)
                framenum += 1
                copyfile(src, dst)


    def onComboTabChanged(self, tab):
        self.comboTabIdx = tab
        self.resetEditPane()


    def onComboFileChanged(self, state, which):
        if state == 0:
            self.metadata["additions"][which] = ""
        else:
            self.metadata["additions"][which] = self.fbxfiles[state - 1]


    # FBX file clicked in list
    def onFbxClicked(self):
        if self.comboTabIdx != 0:
            return
        k = self.fbxlist.currentRow()
        if k >= 0 and k < self.fbxlist.count():
            self.saveCurrentMetadata()
            self.currentCombo = -1
            self.currentFbx = self.fbxlistMap[k]
            fbxfile = self.fbxfiles[self.currentFbx]
            self.metadata = createGetMetaData(fbxfile)
            self.updateListColorIcon()
            self.createMaskEditPane(fbxfile)


    # FBX Filter box changed
    def onFbxFilterChanged(self):
        filt = self.fbxfilter.text().lower()
        if not filt or len(filt) < 1:
            filt = None
        if filt != self.currentFilter:
            self.fillFbxList()
            self.currentFilter = filt


    # FBX file clicked in list
    def onComboClicked(self):
        if self.comboTabIdx != 1:
            return
        k = self.combolist.currentRow()
        if k >= 0 and k < self.combolist.count():
            self.saveCurrentMetadata()
            self.currentCombo = k
            self.currentFbx = -1
            combofile = self.combofiles[self.currentCombo]
            self.metadata = createGetMetaData(combofile)
            self.updateListColorIcon()
            self.createMaskEditPane(combofile)


    def onAddCombo(self):
        file, filter = QFileDialog.getSaveFileName(self, 'Save file', os.path.abspath("."),
                                                   "Mask files (*.json)")
        if file is not None and len(file) > 0:
            combofile = make_path_relative(os.path.abspath("."), os.path.abspath(file))
            print("adding combo", combofile)
            self.saveCurrentMetadata()
            metadata = createGetMetaData(combofile)
            self.fillComboList()
            for idx in range(0, len(self.combofiles)):
                if combofile == self.combofiles[idx]:
                    self.currentCombo = idx
                    break
            if self.currentCombo >= 0:
                self.combolist.setCurrentRow(self.currentCombo)


    def onDelCombo(self):
        pass


    # text field changed
    def onTextFieldChanged(self, text, field):
        if type(self.metadata[field]) is int:
            self.metadata[field] = int(text)
        elif type(self.metadata[field]) is float:
            self.metadata[field] = float(text)
        else:
            self.metadata[field] = text

        critical = critical_mask
        if self.metadata["fbx"].lower().endswith(".json"):
            critical = critical_combo

        if critical(field) and len(text) == 0:
            self.paneWidgets[field].setStyleSheet("border: 1px solid #FF0000;")
        elif desired(field) and len(text) == 0:
            self.paneWidgets[field].setStyleSheet("border: 1px solid #FF7F50;")
        else:
            self.paneWidgets[field].setStyleSheet("border: 0px;")
        self.updateListColorIcon()


    # checkbox changed
    def onCheckboxChanged(self, state, field):
        if state == 0:
            self.metadata[field] = False
        else:
            self.metadata[field] = True
        self.updateListColorIcon()


    # texsize changed
    def onDropdownChanged(self, state, field):
        if type(self.metadata[field]) is int:
            self.metadata[field] = int(DROP_DOWNS[field][state])
        elif type(self.metadata[field]) is float:
            self.metadata[field] = float(DROP_DOWNS[field][state])
        else:
            self.metadata[field] = DROP_DOWNS[field][state]


    # called before exit
    def finalCleanup(self):
        self.cancelledSVN = True
        self.saveCurrentMetadata()

        # This is just getting annoying
        #
        # QApplication.setOverrideCursor(Qt.WaitCursor)
        #needcommit = svnNeedsCommit()
        # QApplication.restoreOverrideCursor()
        #if needcommit:
        #    msg = QMessageBox()
        #    msg.setIcon(QMessageBox.Warning)
        #    msg.setText("You have changed files in your depot.")
        #    msg.setInformativeText("Be sure to commit your changes to avoid conflicts.")
        #    msg.setWindowTitle("Files Changed - SVN Commit Recommended")
        #    msg.setStandardButtons(QMessageBox.Ok)
        #    self.ignoreSVN += 1
        #    self.dialogUp = True
        #    msg.exec_()
        #    self.dialogUp = False

        #
        # WRITE CONFIG
        #
        geo = self.geometry()
        self.config["x"] = geo.x()
        self.config["y"] = geo.y()
        writeMetaData(getConfigFile(), self.config)


    # build
    def onBuild(self):

        QApplication.setOverrideCursor(Qt.WaitCursor)

        if self.currentCombo >= 0:
            # build combo
            combofile = self.combofiles[self.currentCombo]
            buildCombo(combofile, self.outputWindow, self.metadata)
            filetype = "Combo Json"

        else:
            # build mask
            fbxfile = self.fbxfiles[self.currentFbx]
            svnAddFile(fbxfile)
            buildMask(fbxfile, self.outputWindow, self.metadata)
            filetype = "FBX"

        deps, missing = getDependencies(self.metadata)

        for d in deps:
            svnAddFile(d["file"])

        for m in missing:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            msg.setText("This " + filetype +" depends on " + m + ", which cannot be found.")
            msg.setWindowTitle("Missing PNG File")
            msg.setStandardButtons(QMessageBox.Ok)
            self.ignoreSVN += 1
            self.dialogUp = True
            msg.exec_()
            self.dialogUp = False

        QApplication.restoreOverrideCursor()

        self.updateListColorIcon()


    def onAddAddition(self):
        self.ignoreSVN += 1
        self.dialogUp = True
        addn = NewAdditionDialog.go_modal(self)
        self.dialogUp = False
        if addn:
            if "additions" not in self.metadata:
                self.metadata["additions"] = list()
            self.metadata["additions"].append(addn)
            idx = self.addslist.count()
            self.addslist.addItem(addn["type"] + " : " + addn["name"])
            self.addslist.item(idx).setFont(QFont("Arial", 12, QFont.Bold))


    def onEditAddition(self):
        idx = self.addslist.currentRow()
        if idx >= 0:
            self.ignoreSVN += 1
            self.dialogUp = True
            addn = AdditionDialog.go_modal(self, self.metadata["additions"][idx])
            self.dialogUp = False
            if addn:
                self.addslist.item(idx).setText(addn["type"] + " : " + addn["name"])
                self.metadata["additions"][idx] = addn


    def onDelAddition(self):
        idx = self.addslist.currentRow()
        if idx >= 0:
            del self.metadata["additions"][idx]
            i = self.addslist.takeItem(idx)
            i = None


    def onCopyAddition(self):
        idx = self.addslist.currentRow()
        if idx >= 0:
            addn = deepcopy(self.metadata["additions"][idx])
            self.addslist.insertItem(idx + 1, addn["type"] + " : " + addn["name"])
            self.addslist.item(idx + 1).setFont(QFont("Arial", 12, QFont.Bold))
            self.addslist.setCurrentRow(idx + 1)
            self.metadata["additions"].insert(idx + 1, addn)


    def onMoveUpAddition(self):
        idx = self.addslist.currentRow()
        if idx > 0:
            self.addslist.insertItem(idx - 1, self.addslist.takeItem(idx))
            self.addslist.setCurrentRow(idx - 1)
            self.metadata["additions"].insert(idx - 1, self.metadata["additions"].pop(idx))


    def onMoveDownAddition(self):
        idx = self.addslist.currentRow()
        if idx >= 0 and self.addslist.count() > 1 and idx < (self.addslist.count() - 1):
            self.addslist.insertItem(idx + 1, self.addslist.takeItem(idx))
            self.addslist.setCurrentRow(idx + 1)
            self.metadata["additions"].insert(idx + 1, self.metadata["additions"].pop(idx))


    def onCopyAllAdditions(self):
        self.additionsClipboard = deepcopy(self.metadata["additions"])


    def onPasteAllAdditions(self):
        if self.additionsClipboard:
            self.metadata["additions"].extend(deepcopy(self.additionsClipboard))
            for addn in self.additionsClipboard:
                idx = self.addslist.count()
                self.addslist.addItem(addn["type"] + " : " + addn["name"])
                self.addslist.item(idx).setFont(QFont("Arial", 12, QFont.Bold))


    def onFocusChanged(self, old, now):

        if self.cancelledSVN or self.dialogUp:
            return

        if not old and now:

            if self.ignoreSVN > 0:
                self.ignoreSVN -= 1
                return

            if (time.time() - self.lastSVNCheck) < SVN_CHECK_TIME:
                return

            QApplication.setOverrideCursor(Qt.WaitCursor)
            needsup = svnNeedsUpdate()
            QApplication.restoreOverrideCursor()
            self.lastSVNCheck = time.time()
            if needsup:
                msg = QMessageBox()
                msg.setIcon(QMessageBox.Warning)
                msg.setText("Your SVN repository is out of date.")
                msg.setInformativeText("Would you like to sync up now?")
                msg.setWindowTitle("SVN Repository out of date")
                msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
                msg.buttonClicked.connect(lambda i: self.onSyncOk(i))
                self.ignoreSVN += 1
                self.dialogUp = True
                msg.exec_()
                self.dialogUp = False


    def doSVNUpdate(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        arttoolUpdated = svnUpdate(self.outputWindow)
        self.fillFbxList()
        QApplication.restoreOverrideCursor()

        if arttoolUpdated:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            msg.setText("File(s) in the Art Tool have changed.")
            msg.setInformativeText("You should exit the Art Tool now and start it again.")
            msg.setWindowTitle("Art Tool Changed")
            msg.setStandardButtons(QMessageBox.Ok)
            msg.buttonClicked.connect(lambda i: self.onSyncOk(i))
            self.cancelledSVN = True
            msg.exec_()

    def onSyncOk(self, i):
        if i.text() == "OK":
            self.doSVNUpdate()
        else:
            # dont check anymore
            self.cancelledSVN = True

    def doAutobuild(self):

        QApplication.setOverrideCursor(Qt.WaitCursor)

        all_missing = dict()

        for f in self.fbxfiles:
            if doesFileNeedRebuilding(f):
                deps, missing = buildMask(f, self.outputWindow)
                if len(missing) > 0:
                    all_missing[f] = missing

        for f in self.combofiles:
            if doesFileNeedRebuilding(f):
                deps, missing = buildCombo(f, self.outputWindow)
                if len(missing) > 0:
                    all_missing[f] = missing

        for file, missing in all_missing.items():
            for m in missing:
                msg = QMessageBox()
                msg.setIcon(QMessageBox.Warning)
                msg.setText(file +" depends on " + m + ", which cannot be found.")
                msg.setWindowTitle("Missing PNG File")
                msg.setStandardButtons(QMessageBox.Ok)
                self.ignoreSVN += 1
                self.dialogUp = True
                msg.exec_()
                self.dialogUp = False

        QApplication.restoreOverrideCursor()
        self.fillComboList()
        self.fillFbxList()


    def doRebuildAll(self):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Warning)
        msg.setText("WARNING!! This will rebuild ALL THE MASKS!!")
        msg.setInformativeText("Are you abso-f*****g-lutely sure?")
        msg.setWindowTitle("Rebuild Everything")
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msg.buttonClicked.connect(lambda i: self.onRebuildAllOk(i))
        self.ignoreSVN += 1
        self.dialogUp = True
        msg.exec_()
        self.dialogUp = False


    def onRebuildAllOk(self, i):
        if i.text() == "OK":

            QApplication.setOverrideCursor(Qt.WaitCursor)

            all_missing = dict()

            for f in self.fbxfiles:
                deps, missing = buildMask(f, self.outputWindow)
                if len(missing) > 0:
                    all_missing[f] = missing

            for f in self.combofiles:
                deps, missing = buildCombo(f, self.outputWindow)
                if len(missing) > 0:
                    all_missing[f] = missing

            for file, missing in all_missing.items():
                for m in missing:
                    msg = QMessageBox()
                    msg.setIcon(QMessageBox.Warning)
                    msg.setText(file + " depends on " + m + ", which cannot be found.")
                    msg.setWindowTitle("Missing PNG File")
                    msg.setStandardButtons(QMessageBox.Ok)
                    self.ignoreSVN += 1
                    self.dialogUp = True
                    msg.exec_()
                    self.dialogUp = False

            QApplication.restoreOverrideCursor()
            self.fillComboList()
            self.fillFbxList()

        else:
            # dont check anymore
            self.cancelledSVN = True

    def doReleaseMasks(self):
        print("todo release masks")

    def uploadToS3(self):

        # what now
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Warning)
        msg.setText("Upload to S3, or just build index?")
        msg.setWindowTitle("Upload to S3")
        msg.setStandardButtons(QMessageBox.Ok|QMessageBox.Cancel)
        msg.buttonClicked.connect(lambda i: self.onUploadToS3Confirm(i))
        self.ignoreSVN += 1
        self.dialogUp = True
        msg.exec_()
        self.dialogUp = False


    def onUploadToS3Confirm(self, item):

        do_upload = item.text() == "OK"

        metalist = list()
        jsonlist = list()
        for fbxfile in self.fbxfiles:
            mdc, mt = checkMetaDataFile(fbxfile)
            if mdc == CHECKMETA_GOOD:
                metadata = loadMetadataFile(fbxfile)
                d = dict()
                for k in RELEASE_FIELDS:
                    d[k] = metadata[k]
                    if type(d[k]) is str:
                        d[k] = d[k].replace("\n", "").replace("\r", "")
                metalist.append(d)
                jsonlist.append(jsonFromFbx(fbxfile))

        for combofile in self.combofiles:
            mdc, mt = checkMetaDataFile(combofile)
            if mdc == CHECKMETA_GOOD:
                metadata = loadMetadataFile(combofile)
                d = dict()
                for k in RELEASE_FIELDS:
                    d[k] = metadata[k]
                    if type(d[k]) is str:
                        d[k] = d[k].replace("\n", "").replace("\r", "")
                md = getCombinedComboMeta(metadata)
                d["tags"] = md["tags"]
                d["author"] = md["author"]

                metalist.append(d)
                jsonlist.append(combofile)

        for i in range(0,len(metalist)):
            metalist[i]["category"] = metalist[i]["category"].lower()
            metalist[i]["tags"] = metalist[i]["tags"].lower().replace(", ",",")
            metalist[i]["modtime"] = int(os.path.getmtime(jsonlist[i]))
            metalist[i]["author"] = metalist[i]["author"].replace(", ",",")

            if metalist[i]["tags"].endswith(" "):
                metalist[i]["tags"] = metalist[i]["tags"][:-1]
            metalist[i]["name"] = metalist[i]["name"].strip()
            metalist[i]["author"] = metalist[i]["author"].strip()

            if do_upload:
                print("Uploading",jsonlist[i])

                uuid = metalist[i]["uuid"]
                print("  json...")
                s3_upload(jsonlist[i], uuid + ".json")
                print("  png...")
                s3_upload(jsonlist[i].replace(".json",".png"), uuid + ".png")
                print("  gif...")
                s3_upload(jsonlist[i].replace(".json",".gif"), uuid + ".gif")
                print("  mp4...")
                s3_upload(jsonlist[i].replace(".json",".mp4"), uuid + ".mp4")


        file, filter = QFileDialog.getSaveFileName(self, 'Save file', os.path.abspath("."),
                                                   "Mask files (*.json)")
        if file is not None and len(file) > 0:
            writeMetaData(os.path.abspath(file), metalist)


    def onWriteMetadataExcel(self):

        pass

        """
Пример #18
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        self.item_cnt = 0

        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(600, 600)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget

        # 设置菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')
        set_pen_menu = file_menu.addMenu('设置画笔')
        set_pen_color_act = set_pen_menu.addAction('设置画笔颜色')
        set_pen_width_act = set_pen_menu.addAction('设置画笔粗细')
        reset_canvas_act = file_menu.addAction('重置画布')
        exit_act = file_menu.addAction('退出')
        draw_menu = menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        edit_menu = menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')

        # 连接信号和槽函数
        exit_act.triggered.connect(qApp.quit)
        line_naive_act.triggered.connect(self.line_naive_action)
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)
        ellipse_act.triggered.connect(self.ellipse_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)
        clip_cohen_sutherland_act.triggered.connect(
            self.clip_cohen_sutherland_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)
        set_pen_color_act.triggered.connect(self.set_pen_color_action)
        set_pen_width_act.triggered.connect(self.set_pen_width_action)
        reset_canvas_act.triggered.connect(self.reset_canvas_action)

        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(600, 600)
        self.setWindowTitle('CG Demo')

    def line_naive_action(self):
        self.canvas_widget.start_draw_line('Naive')
        self.statusBar().showMessage('Naive算法绘制线段,按住鼠标左键并移动以绘制直线,松开以结束绘制')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_dda_action(self):
        self.canvas_widget.start_draw_line('DDA')
        self.statusBar().showMessage('DDA算法绘制线段,按住鼠标左键并移动以绘制直线,松开以结束绘制')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        self.canvas_widget.start_draw_line('Bresenham')
        self.statusBar().showMessage('Bresenham算法绘制线段,按住鼠标左键并移动以绘制直线,松开以结束绘制')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_dda_action(self):
        self.canvas_widget.start_draw_polygon('DDA')
        self.statusBar().showMessage('DDA算法绘制多边形,点击左键设置控制点,点击右键结束绘制')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_bresenham_action(self):
        self.canvas_widget.start_draw_polygon('Bresenham')
        self.statusBar().showMessage('Bresenham算法绘制多边形,点击左键设置控制点,点击右键结束绘制')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def ellipse_action(self):
        self.canvas_widget.start_draw_ellipse()
        self.statusBar().showMessage('中点圆生成算法绘制椭圆,按住鼠标左键并移动以绘制椭圆,松开以结束绘制')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        self.canvas_widget.start_draw_curve('Bezier')
        self.statusBar().showMessage('Bezier算法绘制曲线,点击左键设置控制点,点击右键结束绘制')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        self.canvas_widget.start_draw_curve('B-spline')
        self.statusBar().showMessage('B-spline算法绘制曲线,点击左键设置控制点,点击右键结束绘制')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def translate_action(self):
        self.canvas_widget.start_translate()
        self.statusBar().showMessage('按住鼠标左键并移动以平移图元,松开以结束平移')

    def rotate_action(self):
        self.canvas_widget.start_rotate()
        self.statusBar().showMessage('按住鼠标左键并移动以旋转图元,松开以结束旋转')

    def scale_action(self):
        self.canvas_widget.start_scale()
        self.statusBar().showMessage('按住鼠标左键并移动以缩放图元,松开以结束缩放')

    def clip_cohen_sutherland_action(self):
        self.canvas_widget.start_clip('Cohen-Sutherland')
        self.statusBar().showMessage('按住鼠标左键并移动以产生裁剪框,松开以裁剪线段')

    def clip_liang_barsky_action(self):
        self.canvas_widget.start_clip('Liang-Barsky')
        self.statusBar().showMessage('按住鼠标左键并移动以产生裁剪框,松开以裁剪线段')

    def set_pen_color_action(self):
        c = QColorDialog.getColor()
        self.canvas_widget.set_pen_color(c)

    def set_pen_width_action(self):
        w, ok = QInputDialog.getInt(self,
                                    '调整粗细',
                                    '输入画笔粗细',
                                    value=self.canvas_widget.pen_width)
        if ok and w:
            self.canvas_widget.set_pen_width(w)

    def reset_canvas_action(self):
        self.item_cnt = 0
        self.canvas_widget.reset_canvas()
        self.list_widget.currentTextChanged.disconnect(
            self.canvas_widget.selection_changed)
        self.list_widget.clear()
        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)
        self.scene.clear()
Пример #19
0
class DifferenceDlg(QDialog):
    """
    This is the dialog box that displays the differences between the export
    file and the reference file.

    exportList and referenceList contains the list of unmatched strings from the
    exported file and reference file respectively.

    fileName refers to the name of the file where the differences are found.
    """
    def __init__(self, parent, exportList, referenceList, fileName):
        super(DifferenceDlg, self).__init__(parent)
        self.parent = parent
        self.fileName = fileName
        self.updatedLines = []

        spacerHeight = 15

        self.tabs = QTabWidget()
        self.tab1 = QWidget()

        self.tabs.addTab(self.tab1, "Export vs Reference")

        description = QLabel("The differences between the files: %s" %
                             fileName)

        g1 = QGridLayout()
        reasonLabel = QLabel("<b>Reason <b>")
        g1.addWidget(reasonLabel, 0, 0, 1, 2)

        qhbL = QHBoxLayout()

        self.listWL = QListWidget()
        for items in exportList:
            # splitedString = items.split(':')
            # lineNo = splitedString[0]
            # eString = splitedString[1]
            # rString = 'Line no: ' + lineNo + ', ' + 'Error String: ' + eString
            self.listWL.addItem(items)
        qhbL.addWidget(self.listWL)

        self.listWR = QListWidget()
        for items in referenceList:
            # splitedString = items.split(',')
            # lineNo = splitedString[0]
            # eString = splitedString[1]
            # rString = 'Line no: ' + lineNo + ', ' + 'Error String: ' + eString
            self.listWR.addItem(items)
        qhbL.addWidget(self.listWR)

        promptLabel = QLabel("Please state reason for change.")
        inputLabel = QLabel("Input reason here:")
        self.reasonInput = QLineEdit()
        self.reasonInput.setPlaceholderText("")

        changeButton = QPushButton("Change")
        changeButton.clicked.connect(self.acceptChange)
        changeAllbutton = QPushButton("Change All")
        changeAllbutton.clicked.connect(self.acceptChangeAll)
        # ignoreButton = QPushButton("Ignore")
        # ignoreButton.clicked.connect(self.ignoreChange)

        g1.addWidget(promptLabel, 1, 0, 1, 1)
        g1.addWidget(inputLabel, 2, 0, 1, 1)
        g1.addWidget(self.reasonInput, 3, 0, 1, 3)
        g1.addWidget(changeButton, 4, 0, 1, 1)
        g1.addWidget(changeAllbutton, 4, 2, 1, 1)
        # g1.addWidget(ignoreButton, 4, 2, 1, 1)
        spaceHx = QSpacerItem(self.width(), spacerHeight)
        g1.addItem(spaceHx, 5, 0, 1, 2)

        self.FinishButton = QPushButton("Finish")
        self.FinishButton.clicked.connect(self.finishEdit)

        l = QVBoxLayout()
        l.addWidget(description)
        l.addWidget(reasonLabel)

        t1Layout = QVBoxLayout()
        t1Layout.addLayout(qhbL)
        t1Layout.addLayout(g1)

        self.tab1.setLayout(t1Layout)

        l.addWidget(self.tabs)
        l.addWidget(self.FinishButton)

        self.setLayout(l)
        self.setFixedSize(1000, 1000)

        self.listWR.setSelectionMode(1)
        self.listWL.setSelectionMode(1)
        self.listWR.clicked.connect(self.listWRClicked)
        self.listWL.clicked.connect(self.listWLClicked)

        self.exec_()

    def listWLClicked(self):
        self.listWR.clearSelection()

    def listWRClicked(self):
        self.listWL.clearSelection()

    def acceptChange(self):
        if len(self.listWR.selectedItems()) > 0:
            msg = QMessageBox()
            msg.setText("Please select from the left side list.")
            msg.exec_()

        if len(self.listWL.selectedItems()) > 0:
            for items in self.listWL.selectedItems():
                # print(items.text()[:items.text().find(":")])
                # print(items.text()[items.text().find(":")+1:])
                lineNo = items.text()[:items.text().find(":")]
                string = items.text()[items.text().find(":") + 1:]
                self.updatedLines.append(items.text())

        self.updateReferenceFile(lineNo, string)
        self.updateChangelog()
        msg2 = QMessageBox()
        msg2.setText("Changes updated in the reference file.")
        msg2.exec_()

    def acceptChangeAll(self):

        items = []
        lineNoList = []
        stringList = []
        i = 0
        while i < self.listWL.count():
            items.append(self.listWL.item(i))
            i += 1

        for item in items:
            lineNo = item.text()[:item.text().find(":")]
            string = item.text()[item.text().find(":") + 1:]
            lineNoList.append(lineNo)
            stringList.append(string)
            self.updatedLines.append(item.text())
            # self.updateReferenceFile(lineNo, string)
        self.updateAllChanges(lineNoList, stringList)

        self.updateChangelog()
        msg = QMessageBox()
        msg.setText("All changes updated in the reference file.")
        msg.exec_()

    def finishEdit(self):
        self.close()

    def updateReferenceFile(self, lineNo, string):
        """

        Parameters
        ----------
        lineNo : the line number of the unmatch string
        string : the correct string

        1.Access the reference folder
        2.read from the error file
        3.Update the error lines
        4.write to the error file

        Returns
        -------

        """

        if getattr(sys, "frozen", False):
            ROOT_DIR = os.path.dirname(sys.executable)
        elif __file__:
            ROOT_DIR = os.path.dirname(__file__)
        originalFilePath = os.path.join(ROOT_DIR, "Reference")
        fileToUpdate = os.path.join(originalFilePath, self.fileName)

        with open(fileToUpdate, "r") as file:
            lines = file.readlines()
            # print(lines)

        stringToAdd = string

        try:
            lines[int(lineNo) - 1]
        except IndexError:
            lines.append("")

        lines[int(lineNo) - 1] = stringToAdd

        with open(fileToUpdate, "w") as file:
            file.writelines(lines)

        print("finish running")

    def updateAllChanges(self, lineNoList, stringList):
        """

        Parameters
        ----------
        lineNo : the line number of the unmatch string
        string : the correct string

        1.Access the reference folder
        2.read from the error file
        3.Update the error lines
        4.write to the error file

        Returns
        -------

        """

        if getattr(sys, "frozen", False):
            ROOT_DIR = os.path.dirname(sys.executable)
        elif __file__:
            ROOT_DIR = os.path.dirname(__file__)
        originalFilePath = os.path.join(ROOT_DIR, "Reference")
        fileToUpdate = os.path.join(originalFilePath, self.fileName)

        with open(fileToUpdate, "r") as file:
            lines = file.readlines()

        i = 0
        while i < len(lineNoList):
            try:
                lines[int(lineNoList[i]) - 1]
            except IndexError:
                lines.append("")

            lines[int(lineNoList[i]) - 1] = stringList[i]
            i += 1

        with open(fileToUpdate, "w") as file:
            file.writelines(lines)

        print("finish running")

    def updateChangelog(self):
        linesToAppend = []

        if getattr(sys, "frozen", False):
            ROOT_DIR = os.path.dirname(sys.executable)
        elif __file__:
            ROOT_DIR = os.path.dirname(__file__)
        changelogfile = os.path.join(ROOT_DIR, "changelogs.txt")

        reason = self.reasonInput.text()
        dateAndTime = datetime.now()
        dt_string = dateAndTime.strftime("%d/%m/%Y %H:%M:%S")
        Divider = "==============================================================\n"
        fileName = self.fileName
        updatedLines = self.updatedLines
        reasonHeader = "Reason for change:"
        differenceHeader = "Differences:"
        fileNameHeader = "Name of file:"

        linesToAppend.append(Divider)
        linesToAppend.append(dt_string + "\n" + "\n")
        linesToAppend.append(fileNameHeader + "\n")
        linesToAppend.append(fileName + "\n" + "\n")
        linesToAppend.append(differenceHeader + "\n")
        for lines in updatedLines:
            linesToAppend.append(lines)
        linesToAppend.append("\n" + reasonHeader + "\n")
        linesToAppend.append(reason + "\n")
        linesToAppend.append(Divider)

        with open(changelogfile, "a") as file:
            file.writelines(linesToAppend)
Пример #20
0
class TAFieldsTab(QWidget):
    def __init__(self, ctx):
        super(TAFieldsTab, self).__init__()
        self.ctx = ctx

        self._table_being_updated = False

        self.create_ui()

    def create_ui(self):
        self.fields_list = QListWidget()
        self.fields_list.itemSelectionChanged.connect(
            self.userchanged_field_list)

        self.mode_group = QGroupBox("Field Mode")

        self.mode_box = QComboBox()
        self.mode_box.addItem("Ignore", 'ignore')
        self.mode_box.addItem("Print Label", 'print')
        self.mode_box.addItem("Cluster", 'cluster')
        self.mode_box.addItem("Diversify", 'diversify')
        self.mode_box.currentIndexChanged.connect(self.userchanged_mode_box)

        echoLayout = QGridLayout()
        echoLayout.addWidget(QLabel("Mode:"), 0, 0)
        echoLayout.addWidget(self.mode_box, 0, 1)
        echoLayout.setHorizontalSpacing(50)
        echoLayout.setColumnStretch(0, 1)
        echoLayout.setColumnStretch(1, 1)
        self.mode_group.setLayout(echoLayout)

        self.terms_group = QGroupBox("Field Values")
        self.terms_layout = QStackedLayout()
        self.terms_layout.addWidget(self.create_empty_term_widget())
        self.terms_layout.addWidget(self.create_table_term_widget())
        self.terms_group.setLayout(self.terms_layout)

        layout = QGridLayout()
        layout.addWidget(self.fields_list, 0, 0, 2, 1)
        layout.addWidget(self.mode_group, 0, 1, 1, 1)
        layout.addWidget(self.terms_group, 1, 1)
        layout.setRowStretch(1, 1)
        self.setLayout(layout)

    def create_empty_term_widget(self):
        label = QLabel("Only applied for diversify and cluster categories.")
        label.setAlignment(Qt.AlignCenter)

        return label

    def create_table_term_widget(self):
        self.terms_table = QTableWidget(0, 2)
        self.terms_table.setHorizontalHeaderLabels(
            ['Terms Found', 'Terms Usage'])
        self.terms_table.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.Stretch)
        self.terms_table.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)
        self.terms_table.cellChanged.connect(self.userchanged_table)

        return self.terms_table

    def display_none(self):
        self.fields_list.clearSelection()
        self.status_mode_box(False)
        self.status_terms_group(False)

    def get_current_field_index(self):
        return self.fields_list.currentItem().data(Qt.UserRole)

    def init_field(self, j):
        if j not in self.ctx.app_data.fields:
            mode = 'ignore'
            terms = [[t, t] for t in self.ctx.app_data_manager.get_terms(j)]
            self.ctx.app_data.fields[j] = {'mode': mode, 'terms': terms}
        else:
            for t in self.ctx.app_data_manager.get_terms(j):
                if not any(a[0] == t
                           for a in self.ctx.app_data.fields[j]['terms']):
                    self.ctx.app_data.fields[j]['terms'].append([t, t])
            for k, term_usage in enumerate(
                    self.ctx.app_data.fields[j]['terms']):
                if term_usage[0] not in self.ctx.app_data_manager.get_terms(j):
                    self.ctx.app_data.fields[j]['terms'].pop(k)

    def update_fields_list(self):
        self._field_list_being_updated = True

        self.fields_list.clear()
        for j, cat in enumerate(self.ctx.app_data.peopledata_keys):
            new_item = QListWidgetItem()
            new_item.setData(Qt.UserRole, j)
            new_item.setText(cat)
            self.fields_list.addItem(new_item)

        self._field_list_being_updated = False

    def update_mode_box(self, j):
        index = self.mode_box.findData(self.ctx.app_data.fields[j]['mode'])
        self.mode_box.setCurrentIndex(index)

    def update_terms_group(self, j):
        self._table_being_updated = True
        self.terms_table.setRowCount(len(self.ctx.app_data.fields[j]['terms']))
        for k, term_usage in enumerate(self.ctx.app_data.fields[j]['terms']):
            item_col0 = QTableWidgetItem(term_usage[0])
            item_col0.setFlags(Qt.ItemIsSelectable)
            self.terms_table.setItem(k, 0, item_col0)
            self.terms_table.setItem(k, 1, QTableWidgetItem(term_usage[1]))
        self._table_being_updated = False

    def status_mode_box(self, status):
        self.mode_group.setDisabled(not status)

    def status_terms_group(self, status):
        self.terms_group.setDisabled(not status)
        self.terms_layout.setCurrentIndex(1 if status else 0)

    def userchanged_field_list(self):
        if self._field_list_being_updated: return
        j = self.get_current_field_index()
        self.init_field(j)

        self.update_mode_box(j)
        self.update_terms_group(j)

        self.status_mode_box(True)
        mode = self.ctx.app_data.fields[j]['mode']
        self.status_terms_group(True if mode in
                                ['cluster', 'diversify'] else False)

    def userchanged_mode_box(self, index):
        j = self.get_current_field_index()
        mode = self.mode_box.currentData()

        self.ctx.app_data.fields[j]['mode'] = mode

        mode = self.ctx.app_data.fields[j]['mode']
        self.status_terms_group(True if mode in
                                ['cluster', 'diversify'] else False)

        self.ctx.window.tabs.fields_update()

    def userchanged_table(self, k, l):
        if self._table_being_updated: return
        j = self.get_current_field_index()
        self.ctx.app_data.fields[j]['terms'][k][1] = self.terms_table.item(
            k, l).text()
Пример #21
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        cglog.log("-----------------------------------")
        cglog.log("Start System")
        self.item_cnt = 0
        # if not to set much larger Canvas will lead to
        # can not draw beyond original place
        # self.width = 2000
        # self.height = 2000
        self.width = 600
        self.height = 600
        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(600, 600)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget
        # self.scene = QGraphicsScene(self)
        # self.scene.setSceneRect(0, 0, self.width, self.height)
        # self.canvas_widget = MyCanvas(self.scene, self)
        # self.canvas_widget.setFixedSize(self.width, self.height)
        # self.canvas_widget.main_window = self
        # self.canvas_widget.list_widget = self.list_widget
        self.canvas_widget.setHorizontalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)
        self.canvas_widget.setVerticalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)
        # 设置菜单栏
        self.menubar = self.menuBar()
        file_menu = self.menubar.addMenu('文件')
        set_pen_act = file_menu.addAction('设置画笔')
        reset_canvas_act = file_menu.addAction('重置画布')
        clear_canvas_act = file_menu.addAction('清空画布')
        save_canvas_act = file_menu.addAction('保存画布')
        exit_act = file_menu.addAction('退出')

        draw_menu = self.menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        edit_menu = self.menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')

        #拓展功能的定义位置#.setShortcut("Ctrl+C")
        # I bind the shortcut here which can be triggered here
        self.Additional_function_menu = self.menubar.addMenu('附加功能')
        mouese_select_act = self.Additional_function_menu.addAction('鼠标选择图元')
        copy_act = self.Additional_function_menu.addAction('复制')
        copy_act.setShortcut("Ctrl+C")
        paste_act = self.Additional_function_menu.addAction("粘贴")
        paste_act.setShortcut("Ctrl+V")
        delete_act = self.Additional_function_menu.addAction("删除")
        delete_act.setShortcut("Ctrl+D")
        free_draw_act = self.Additional_function_menu.addAction("自由绘制")
        free_draw_act.setShortcut("Ctrl+F")

        # 关于菜单和窗口操作的信号绑定
        exit_act.triggered.connect(self.quit_box)
        set_pen_act.triggered.connect(self.set_pen)
        mouese_select_act.triggered.connect(self.select_item_action)
        copy_act.triggered.connect(self.copy_action)
        paste_act.triggered.connect(self.paste_action)
        delete_act.triggered.connect(self.delete_action)
        free_draw_act.triggered.connect(self.free_draw_action)

        clear_canvas_act.triggered.connect(self.clear_canvas)
        save_canvas_act.triggered.connect(self.save_canvas)
        reset_canvas_act.triggered.connect(self.reset_canvas_action)
        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)

        # 直线绘制算法的信号绑定
        line_naive_act.triggered.connect(self.line_naive_action)
        line_dda_act.triggered.connect(self.line_DDA_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)

        # 椭圆绘制算法信号绑定
        ellipse_act.triggered.connect(self.ellipse_action)

        # 多边形绘制算法信号绑定
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)

        # 曲线绘制算法的信号绑定
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)

        # 关于编辑的算法信号绑定
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)

        # 裁剪算法信号绑定
        clip_cohen_sutherland_act.triggered.connect(
            self.clip_cohen_sutherland_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)

        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(self.width, self.height)
        self.setWindowTitle('CG Demo')

        # self.width=600
        # self.height=600
        # self.scene = QGraphicsScene(self)
        # self.scene.setSceneRect(0, 0, self.width, self.height)
        # self.canvas_widget.resize(self.width, self.height)
        # self.canvas_widget.setFixedSize(self.width, self.height)
        # self.statusBar().showMessage('空闲')
        # self.setMaximumHeight(self.height)
        # self.setMaximumWidth(self.width)
        # self.resize(self.width, self.height)

    def get_id(self):
        _id = str(self.item_cnt)
        self.item_cnt += 1
        return _id

    def copy_action(self):
        self.canvas_widget.copy_item()
        self.statusBar().showMessage('复制操作')

    def paste_action(self):
        self.canvas_widget.paste_item()
        self.statusBar().showMessage('粘贴操作')

    def delete_action(self):
        self.canvas_widget.delete_item()
        self.statusBar().showMessage('删除操作')

    def reset_canvas_action(self):
        print("Reset canvas")
        self.item_cnt = 0
        self.statusBar().showMessage('重置画布')
        dialog = QDialog()
        dialog.setWindowTitle('重置画布')
        formlayout = QFormLayout(dialog)
        widthEdit = QLineEdit()
        heightEdit = QLineEdit()
        formlayout.addRow("width", widthEdit)
        formlayout.addRow("height", heightEdit)
        box3 = QDialogButtonBox(QDialogButtonBox.Ok)
        box3.accepted.connect(dialog.accept)
        formlayout.addRow(box3)
        if dialog.exec():
            width = widthEdit.text()
            height = heightEdit.text()
            if len(width) == 0 or len(height) == 0:
                QMessageBox.about(self, "Warning", "input number empty!   ")
                return
            if width.isdigit() and height.isdigit():
                if int(width) < 1000 and int(width) > 100 and int(
                        height) < 1000 and int(height) > 100:
                    self.width = int(width)
                    self.height = int(height)
                else:
                    QMessageBox.about(
                        self, "Warning",
                        "input number is out of range (100-1000 Only)!   ")
                    return
            else:
                QMessageBox.about(self, "Warning",
                                  "input number is not integer!   ")
                return
            # print(self.width,self.height)
            # self.w = self.width
            # self.h = self.height

            self.canvas_widget.clear_canvas()
            self.list_widget.clearSelection()
            self.canvas_widget.clear_selection()
            self.list_widget.clear()

            #self.scene = QGraphicsScene(self)
            self.scene.setSceneRect(0, 0, self.width, self.height)
            self.canvas_widget.resize(self.width, self.height)
            self.canvas_widget.setFixedSize(self.width, self.height)

            self.statusBar().showMessage('空闲')
            self.setMaximumHeight(self.height)
            self.setMaximumWidth(self.width)
            self.resize(self.width, self.height)

    def line_naive_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_line('Naive', self.get_id())
        self.statusBar().showMessage('Naive算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_DDA_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_line('DDA', self.get_id())
        self.statusBar().showMessage('DDA算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_line('Bresenham', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def ellipse_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_ellipse(self.get_id())
        self.statusBar().showMessage('绘制椭圆')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_dda_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_polygon('DDA', self.get_id())
        self.statusBar().showMessage('DDA算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_bresenham_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_polygon('Bresenham', self.get_id())
        self.statusBar().showMessage('Bresenham算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_curve('Bezier', self.get_id())
        self.statusBar().showMessage('Bezier算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.canvas_widget.start_draw_curve('B-spline', self.get_id())
        self.statusBar().showMessage('b_spline算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def select_item_action(self):
        self.statusBar().showMessage("使用鼠标选择图元")
        self.canvas_widget.start_select()

    def clear_canvas(self):
        self.statusBar().showMessage("清空画布")
        self.list_widget.clear()
        self.canvas_widget.clear_canvas()

    def save_canvas(self):
        self.statusBar().showMessage("保存画布")
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        self.statusBar().showMessage('保存画布')
        dialog = QFileDialog()
        filename = dialog.getSaveFileName(
            filter="Image Files(*.jpg *.png *.bmp)")
        if filename[0]:
            res = self.canvas_widget.grab(
                self.canvas_widget.sceneRect().toRect())
            res.save(filename[0])

    def set_pen(self):
        # use this fuction to set pen's color
        self.statusBar().showMessage("设置画笔")
        col = QColorDialog.getColor()
        if col.isValid():
            self.canvas_widget.set_pen_color(col)
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def translate_action(self):
        self.canvas_widget.start_translate()
        self.statusBar().showMessage('平移')

    def rotate_action(self):
        self.canvas_widget.start_rotate()
        self.statusBar().showMessage('旋转')

    def scale_action(self):
        self.canvas_widget.start_scale()
        self.statusBar().showMessage('缩放')

    def clip_cohen_sutherland_action(self):
        self.canvas_widget.start_clip_cohen_sutherland()
        self.statusBar().showMessage('裁剪cohen_sutherland')

    def clip_liang_barsky_action(self):
        self.canvas_widget.start_clip_liang_barsky()
        self.statusBar().showMessage('裁剪liang_barsky')

    def free_draw_action(self):
        if (self.item_cnt > 0):
            self.item_cnt -= 1
        self.statusBar().showMessage('自由绘制')
        self.canvas_widget.draw_free(self.get_id())

    def quit_box(self):
        reply = QMessageBox.question(self, 'CG System', "是否要保存画布",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.save_canvas()
        qApp.quit()
        # else:
        #     event.ignore()

    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'CG System', "是否要保存画布",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.save_canvas()
        qApp.quit()
Пример #22
0
class TrainTab(QWidget):

    def __init__(self):
        super().__init__()

        self.available_models = []
        self.model = None
        self.model_dir = None
        self.weights_name = None
        self.highlighted_data = None
        self.batch_size = 50
        self.epochs = 100

        self.initUI()
    
    def initUI(self):
        self.train_button = QPushButton("Train")
        self.train_button.toggle()
        self.train_button.setCheckable(True)
        self.train_button.setEnabled(False)
        self.train_button.clicked.connect(self.toggle_train_button)

        self.weights_name_field = QLineEdit()
        self.weights_name_field.textChanged.connect(self.weights_name_changed)
        self.weights_name_field.setEnabled(False)

        self.data_list = QListWidget()
        self.data_list.setEnabled(False)
        self.data_list.itemClicked.connect(self.highlight_available_data)

        self.added_data_list = QListWidget()
        self.added_data_list.setEnabled(False)
        self.added_data_list.itemClicked.connect(self.highlight_added_data_list)

        self.move_data_button = QPushButton("<< >>")
        self.move_data_button.clicked.connect(self.move_data)
        self.move_data_button.setEnabled(False)

        batch_size_widget = QLineEdit(str(self.batch_size))
        batch_size_widget.setValidator(QIntValidator())
        batch_size_widget.textChanged.connect(lambda new_val: self.line_edit_value_changed(new_val, "batch_size"))

        epochs_widget = QLineEdit(str(self.epochs))
        epochs_widget.setValidator(QIntValidator())
        epochs_widget.textChanged.connect(lambda new_val: self.line_edit_value_changed(new_val, "epochs"))

        model_list = self.init_model_list()

        menu_widget = QWidget()
        menu_layout = QGridLayout()
        menu_layout.setColumnStretch(1, 1)
        menu_layout.setColumnStretch(2, 2)
        menu_layout.setColumnStretch(3, 1)
        menu_layout.setColumnStretch(4, 2)
        menu_layout.setColumnStretch(5, 2)
        menu_layout.addWidget(QWidget())
        menu_layout.addWidget(QLabel("Select model: "), 1, 1)
        menu_layout.addWidget(model_list, 1, 2)
        menu_layout.addWidget(QLabel("Available data:"), 2, 2, Qt.AlignCenter)
        menu_layout.addWidget(QLabel("Selected data:"), 2, 4, Qt.AlignCenter)
        menu_layout.addWidget(QLabel("Select data: "), 3, 1)
        menu_layout.addWidget(self.data_list, 3, 2)
        menu_layout.addWidget(self.move_data_button, 3, 3)
        menu_layout.addWidget(self.added_data_list, 3, 4)        
        menu_layout.addWidget(QLabel("Batch size: "), 4, 1)
        menu_layout.addWidget(batch_size_widget, 4, 2)
        menu_layout.addWidget(QLabel("Epochs: "), 5, 1)
        menu_layout.addWidget(epochs_widget, 5, 2)
        menu_layout.addWidget(QLabel("Name for weights: "), 6,1)
        menu_layout.addWidget(self.weights_name_field, 6,2)
        menu_layout.addWidget(self.train_button, 7, 1)
        menu_layout.addWidget(QWidget())
        menu_widget.setLayout(menu_layout)
        
        main_layout = QVBoxLayout()
        main_layout.addWidget(menu_widget)
        self.setLayout(main_layout)

    def init_model_list(self):        
        model_list = QComboBox()
        model_list.activated.connect(self.select_model)
        models_path = Path(os.getcwd()) / "models"
        for model_folder in models_path.iterdir():
            if not model_folder.is_dir() or model_folder.name == "__pycache__":
                continue
            model_list.addItem(model_folder.name)
            self.available_models.append(model_folder)
        if self.available_models:
            self.select_model(0)     
        return model_list

    def toggle_train_button(self):
        if self.train_button.isChecked():
            self.train_button.setStyleSheet("background-color: orange")
            self.train_button.setEnabled(False)
            QApplication.processEvents()
            self.train()

    def select_model(self, idx):
        self.model_dir = self.available_models[idx]
        module_path = str((self.model_dir / "model.py").absolute())
        spec = importlib.util.spec_from_file_location("model", module_path)
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)
        self.model = module.KodoModel()
        self.weights_name_field.setEnabled(True)
        self.refresh_data_list()

    def weights_name_changed(self, new_name):
        if not self.weights_name:
            self.train_button.setEnabled(True)
        self.weights_name = new_name

    def refresh_data_list(self):
        self.move_data_button.setEnabled(True)
        self.added_data_list.setEnabled(True)
        self.data_list.setEnabled(True)
        data_path = self.model_dir / "data"
        self.data_list.clear()
        for data in data_path.iterdir():
            if not data.is_dir() or data.name == "__pycache__":
                continue
            self.data_list.addItem(data.name)

    def highlight_available_data(self, item):
        self.highlighted_data = item.text()
        self.added_data_list.clearSelection()
    
    def highlight_added_data_list(self, item):
        self.highlighted_data = item.text()
        self.data_list.clearSelection()

    def move_data(self):
        if self.is_in_qlist(self.highlighted_data, self.data_list):
            self.remove_from_qlist(self.highlighted_data, self.data_list)
            self.added_data_list.addItem(self.highlighted_data)
            if self.data_list.currentItem():
                self.highlighted_data = self.data_list.currentItem().text()
        else:
            self.remove_from_qlist(self.highlighted_data, self.added_data_list)
            self.data_list.addItem(self.highlighted_data)
            if self.added_data_list.currentItem():
                self.highlighted_data = self.added_data_list.currentItem().text()


    def is_in_qlist(self, text, qlist):
        for idx in range(qlist.count()):
            item = qlist.item(idx)
            if item.text() == text:
                return True
        return False

    def remove_from_qlist(self, text, qlist):
        for idx in range(qlist.count()):
            item = qlist.item(idx)
            if item.text() == text:
                qlist.takeItem(idx)
                break

    def get_added_data_names(self):
        names = []
        for idx in range(self.added_data_list.count()):
            name = self.added_data_list.item(idx).text()
            names.append(name)
        return names

    def stack_data(self):
        info = None
        data_lists = []
        for name in self.get_added_data_names():
            data_path = self.model_dir / "data" / name
            if not data_lists:
                for idx, data in enumerate(self.model.load_processed_data(data_path)):
                    data_lists.append([data])
            else:
                for idx, data in enumerate(self.model.load_processed_data(data_path)):
                    data_lists[idx].append(data)
        with open(data_path / "info.json") as fp:
            info = json.load(fp)
        stacks = []
        for data_list in data_lists:
            stacks.append(np.concatenate(data_list, axis=0))
        stacks.append(info)
        return stacks

    def train(self):
        self.model.load_data_into_variables(self.stack_data())
        self.model.create_model()
        self.model.train(batch_size=self.batch_size, epochs=self.epochs, weights_name=self.weights_name)
        self.train_button.setChecked(False)
        self.train_button.setEnabled(True)
        self.train_button.setStyleSheet("")
        
    def line_edit_value_changed(self, new_val, variable_name):
        try:
            # Segmentation fault if screen_capture_size set to 1
            if int(new_val) > 1:
                setattr(self, variable_name, int(new_val))
        except ValueError:
            pass
Пример #23
0
class VarTabWidgetDemo(QWidget):
    def __init__(self, data_list):
        super(VarTabWidgetDemo, self).__init__()
        self.initUI(data_list)

    def initUI(self, data_list):
        self.resize(800, 800)
        self.setWindowTitle('变量设置')
        self.signal = MySignal()
        icon = QIcon()
        icon.addPixmap(QPixmap('./image/设置.png'))
        self.setWindowIcon(icon)
        self.label1 = QLabel('变量')
        self.label2 = QLabel('自变量')
        self.label3 = QLabel('因变量')

        self.list_widget1 = QListWidget()
        self.list_widget2 = QListWidget()
        self.list_widget3 = QListWidget()

        self.list_widget1.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_widget2.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_widget3.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_widget1.addItems([str(item) for item in data_list])

        self.button12 = QPushButton('-->')

        self.button13 = QPushButton('-->')

        vlayout1 = QVBoxLayout()
        vlayout1.addWidget(self.button12)

        hlayout1 = QHBoxLayout()
        hlayout1.addItem(vlayout1)
        vlayout = QVBoxLayout()
        top_hlayout2 = QHBoxLayout()
        self.checkBox2 = QCheckBox('全选')
        top_hlayout2.addWidget(self.label2)
        top_hlayout2.addWidget(self.checkBox2)
        top_hlayout2.addStretch()
        vlayout.addLayout(top_hlayout2)
        vlayout.addWidget(self.list_widget2)
        vlayout.setSpacing(10)
        hlayout1.addItem(vlayout)

        vlayout2 = QVBoxLayout()
        vlayout2.addWidget(self.button13)

        hlayout2 = QHBoxLayout()
        hlayout2.addItem(vlayout2)
        vlayout = QVBoxLayout()

        top_hlayout3 = QHBoxLayout()
        self.checkBox3 = QCheckBox('全选')
        top_hlayout3.addWidget(self.label3)
        top_hlayout3.addWidget(self.checkBox3)
        top_hlayout3.addStretch()
        vlayout.addLayout(top_hlayout3)
        vlayout.addWidget(self.list_widget3)
        vlayout.setSpacing(10)
        hlayout2.addItem(vlayout)

        gridlayout = QGridLayout()
        hlayout = QHBoxLayout()
        hlayout.setSpacing(20)

        vlayout = QVBoxLayout()
        vlayout.addItem(hlayout)
        top_hlayout1 = QHBoxLayout()
        self.checkBox1 = QCheckBox('全选')
        top_hlayout1.addWidget(self.label1)
        top_hlayout1.addWidget(self.checkBox1)
        top_hlayout1.addStretch()
        vlayout.addLayout(top_hlayout1)
        vlayout.addWidget(self.list_widget1)
        vlayout.setSpacing(10)

        gridlayout.addItem(vlayout, 1, 0, 2, 1)
        hlayout1.setSpacing(10)
        hlayout2.setSpacing(10)
        gridlayout.addItem(hlayout1, 1, 1, 1, 1)
        gridlayout.addItem(hlayout2, 2, 1, 1, 1)
        self.setLayout(gridlayout)

        self.button12.clicked.connect(self.onClickButton12)
        self.button13.clicked.connect(self.onClickButton13)

        self.list_widget1.setObjectName('list_widget1')
        self.list_widget2.setObjectName('list_widget2')
        self.list_widget3.setObjectName('list_widget3')
        self.list_widget1.setToolTip('按住Ctrl键可用鼠标多选哦!')
        self.list_widget2.setToolTip('按住Ctrl键可用鼠标多选哦!')
        self.list_widget3.setToolTip('按住Ctrl键可用鼠标多选哦!')
        self.list_widget1.itemClicked.connect(self.focusList)
        self.list_widget2.itemClicked.connect(self.focusList)
        self.list_widget3.itemClicked.connect(self.focusList)
        self.list_widget1.itemSelectionChanged.connect(self.focusList)
        self.list_widget2.itemSelectionChanged.connect(self.focusList)
        self.list_widget3.itemSelectionChanged.connect(self.focusList)

        self.checkBox1.stateChanged.connect(self.checkBoxStatus)
        self.checkBox2.stateChanged.connect(self.checkBoxStatus)
        self.checkBox3.stateChanged.connect(self.checkBoxStatus)

    #鼠标在特定list_widget操作时改变按钮显示的操作方向
    def focusList(self):
        sender = self.sender().objectName()
        if sender == 'list_widget1':
            if self.button12.text() != '-->':
                self.button12.setText('-->')
            if self.button13.text() != '-->':
                self.button13.setText('-->')
        elif sender == 'list_widget2':
            if self.button12.text() != '<--':
                self.button12.setText('<--')
        else:
            if self.button13.text() != '<--':
                self.button13.setText('<--')

    def onClickButton12(self):
        if self.button12.text() == '-->':
            sender = self.list_widget1
            reciever = self.list_widget2
        else:
            sender = self.list_widget2
            reciever = self.list_widget1
        if sender is not None and reciever is not None:
            self.sendData(sender, reciever)

    def onClickButton13(self):
        sender, reciever = None, None
        if self.button13.text() == '-->':
            sender = self.list_widget1
            reciever = self.list_widget3
        else:
            sender = self.list_widget3
            reciever = self.list_widget1
        if sender is not None and reciever is not None:
            self.sendData(sender, reciever)

    def sendData(self, sender, reciever):
        try:
            item_list = sender.selectedItems()
            for item in item_list:
                reciever.addItem(item.text())
                sender.takeItem(sender.row(item))
                self.initCheckBox()
        except Exception as e:
            print(e)

    def checkBoxStatus(self):
        sender = self.sender()
        if (sender == self.checkBox1):
            if self.checkBox1.isChecked():
                self.list_widget1.selectAll()
            else:
                self.list_widget1.clearSelection()
        elif (sender == self.checkBox2):
            if self.checkBox2.isChecked():
                self.list_widget2.selectAll()
            else:
                self.list_widget2.clearSelection()
        else:
            if self.checkBox1.isChecked():
                self.list_widget3.selectAll()
            else:
                self.list_widget3.clearSelection()

    def initCheckBox(self):
        self.checkBox1.setChecked(False)
        self.checkBox2.setChecked(False)
        self.checkBox3.setChecked(False)

    def getVarDict(self):
        count1 = self.list_widget2.count()
        count2 = self.list_widget3.count()
        independ_var = [
            self.list_widget2.item(i).text() for i in range(count1)
        ]
        depend_var = [self.list_widget3.item(i).text() for i in range(count2)]
        var_dict = {'independ_var': independ_var, 'depend_var': depend_var}
        return var_dict
Пример #24
0
class ConfigureStorageDialog(QDialog):
    WIDTH_INCREMENT = 10
    HEIGHT_INCREMENT = 100

    def __init__(self, storage: _st.StorageTank, parent: _ed.Editor):
        super().__init__(parent)
        self.parent = parent
        self.storage = storage
        self.n = 0
        self.m = 0

        spacerHeight = 15

        self.tabs = QTabWidget()
        self.tab1 = QWidget()
        self.tab2 = QWidget()

        self.tabs.addTab(self.tab1, "Heat exchangers")
        self.tabs.addTab(self.tab2, "Direct ports")

        h0 = QHBoxLayout()
        description = QLabel("Please configure the storage tank:")
        exportButton = QPushButton("Export ddck")
        exportButton.clicked.connect(self.storage.exportDck)

        h0.addWidget(description)
        h0.addWidget(exportButton)

        tankNameLabel = QLabel()
        tankNameLabel.setText("<b>Tank name: </b>")
        self.le = QLineEdit(self.storage.label.toPlainText())

        gl = QGridLayout()
        hxsLabel = QLabel("<b>Heat Exchangers </b>")
        gl.addWidget(hxsLabel, 0, 0, 1, 2)

        qhbL = QHBoxLayout()

        self.leftHeatExchangersItemListWidget = QListWidget()
        qhbL.addWidget(self.leftHeatExchangersItemListWidget)

        self.rightHeatExchangersItemListWidget = QListWidget()
        qhbL.addWidget(self.rightHeatExchangersItemListWidget)

        offsetLabel = QLabel("Height offsets in percent")
        offsetLeILabel = QLabel("Input (upper port): ")
        offsetLeOLabel = QLabel("Output (lower port):")
        self.offsetLeI = QLineEdit("0")
        self.offsetLeO = QLineEdit("0")
        self.lButton = QRadioButton("Left side")
        self.rButton = QRadioButton("Right side")

        gl.addWidget(offsetLabel, 3, 0, 1, 1)
        gl.addWidget(offsetLeILabel, 4, 0, 1, 1)
        gl.addWidget(self.offsetLeI, 5, 0, 1, 3)
        gl.addWidget(offsetLeOLabel, 6, 0, 1, 1)
        gl.addWidget(self.offsetLeO, 7, 0, 1, 3)

        self.hxNameLe = QLineEdit()
        self.hxNameLe.setPlaceholderText("Enter a name...")
        gl.addWidget(self.hxNameLe, 8, 0, 1, 3)

        gl.addWidget(self.lButton, 9, 0, 1, 1)
        gl.addWidget(self.rButton, 9, 2, 1, 1)

        addButton = QPushButton("Add...")
        addButton.clicked.connect(self.addHx)
        gl.addWidget(addButton, 10, 0, 1, 1)
        removeButton = QPushButton("Remove...")
        removeButton.clicked.connect(self.removeHxL)
        removeButton.clicked.connect(self.removeHxR)
        gl.addWidget(removeButton, 10, 1, 1, 1)
        modifyButton = QPushButton("Modify")
        modifyButton.clicked.connect(self.modifyHx)
        gl.addWidget(modifyButton, 10, 2, 1, 1)
        spaceHx = QSpacerItem(self.width(), spacerHeight)
        gl.addItem(spaceHx, 11, 0, 1, 2)

        manPortLay = QVBoxLayout()
        qhbL2 = QHBoxLayout()

        self._leftDirectPortPairsItemListWidget = QListWidget()
        qhbL2.addWidget(self._leftDirectPortPairsItemListWidget)

        self._rightDirectPortPairsItemListWidget = QListWidget()
        qhbL2.addWidget(self._rightDirectPortPairsItemListWidget)

        manPortLay.addLayout(qhbL2)

        manPortLabel = QLabel("<b>Set port manually</b>")
        manPortLabel2 = QLabel("Enter height in percent: ")
        portlabelUpper = QLabel("Inlet")
        self.manPortLeI = QLineEdit("0")
        portlabelLower = QLabel("Outlet")
        self.manPortLeO = QLineEdit("0")

        qhbl3 = QHBoxLayout()
        self.manlButton = QRadioButton("Left side")
        self.manrButton = QRadioButton("Right side")
        qhbl3.addWidget(self.manlButton)
        qhbl3.addWidget(self.manrButton)

        self.manAddButton = QPushButton("Add (manual) ports")
        self.manAddButton.clicked.connect(self.addPortPair)

        self.manRemovebutton = QPushButton("Remove ports")
        self.manRemovebutton.clicked.connect(self.removePortPairLeft)
        self.manRemovebutton.clicked.connect(self.removePortPairRight)

        self.modifyPortButton = QPushButton("Modify")
        self.modifyPortButton.clicked.connect(self.modifyPort)

        addRemoveButtons = QHBoxLayout()
        addRemoveButtons.addWidget(self.manAddButton)
        addRemoveButtons.addWidget(self.manRemovebutton)
        addRemoveButtons.addWidget(self.modifyPortButton)

        manPortLay.addWidget(manPortLabel)
        manPortLay.addWidget(manPortLabel2)
        manPortLay.addWidget(portlabelUpper)
        manPortLay.addWidget(self.manPortLeI)
        manPortLay.addWidget(portlabelLower)
        manPortLay.addWidget(self.manPortLeO)
        manPortLay.addLayout(qhbl3)
        manPortLay.addLayout(addRemoveButtons)

        increaseSizeButton = QPushButton("Increase size")
        decreaseSizeButton = QPushButton("Decrease size")
        self.okButton = QPushButton("OK")
        self.cancelButton = QPushButton("Cancel")

        increaseSizeButton.clicked.connect(self.incrSize)
        decreaseSizeButton.clicked.connect(self.decrSize)
        self.okButton.clicked.connect(self.acceptedEdit)
        self.cancelButton.clicked.connect(self.cancel)

        L = QVBoxLayout()
        L.addLayout(h0)
        L.addWidget(tankNameLabel)
        L.addWidget(self.le)

        t1Layout = QVBoxLayout()
        t1Layout.addLayout(qhbL)
        t1Layout.addLayout(gl)

        self.tab1.setLayout(t1Layout)

        self.tab2.setLayout(manPortLay)

        L.addWidget(self.tabs)

        L.addWidget(increaseSizeButton)
        L.addWidget(decreaseSizeButton)
        L.addWidget(self.okButton)
        L.addWidget(self.cancelButton)

        self.setLayout(L)

        self._loadHeatExchangers()
        self._loadDirectPortPairs()

        # This is to ensure that only one list element is selected
        self.rightHeatExchangersItemListWidget.setSelectionMode(1)
        self.leftHeatExchangersItemListWidget.setSelectionMode(1)
        self.rightHeatExchangersItemListWidget.clicked.connect(
            self.listWRClicked)
        self.leftHeatExchangersItemListWidget.clicked.connect(
            self.listWLClicked)

        self._rightDirectPortPairsItemListWidget.setSelectionMode(1)
        self._leftDirectPortPairsItemListWidget.setSelectionMode(1)
        self._rightDirectPortPairsItemListWidget.clicked.connect(
            self.listWR2Clicked)
        self._leftDirectPortPairsItemListWidget.clicked.connect(
            self.listWL2Clicked)

        self.show()

    def _loadHeatExchangers(self):
        self.leftHeatExchangersItemListWidget.clear()
        self.rightHeatExchangersItemListWidget.clear()

        for heatExchanger in self.storage.heatExchangers:
            itemText = self._getHeatExchangerListItemText(heatExchanger)
            item = QListWidgetItem(itemText)
            item.setData(_qtc.Qt.UserRole, heatExchanger)

            if heatExchanger.sSide == 0:
                self.leftHeatExchangersItemListWidget.addItem(item)
            else:
                self.rightHeatExchangersItemListWidget.addItem(item)

    @staticmethod
    def _getHeatExchangerListItemText(h):
        return (h.displayName + ", y_offset = " +
                "%d" % int(h.relativeInputHeight * 100) + "%" + " to " +
                "%d" % int(h.relativeOutputHeight * 100) + "%")

    def _loadDirectPortPairs(self):
        self._leftDirectPortPairsItemListWidget.clear()
        self._rightDirectPortPairsItemListWidget.clear()

        directPortPair: _dpp.DirectPortPair
        for directPortPair in self.storage.directPortPairs:
            itemText = self._getDirectPortPairListItemText(directPortPair)
            item = QListWidgetItem(itemText)
            item.setData(_qtc.Qt.UserRole, directPortPair)

            if directPortPair.side.isLeft:
                self._leftDirectPortPairsItemListWidget.addItem(item)
            else:
                self._rightDirectPortPairsItemListWidget.addItem(item)

    @staticmethod
    def _getDirectPortPairListItemText(directPortPair: _dpp.DirectPortPair):
        return ("Port pair from " +
                "%d%%" % int(directPortPair.relativeInputHeight * 100) +
                " to " +
                "%d%%" % int(directPortPair.relativeOutputHeight * 100))

    def listWLClicked(self):
        self.rightHeatExchangersItemListWidget.clearSelection()

    def listWRClicked(self):
        self.leftHeatExchangersItemListWidget.clearSelection()

    def listWL2Clicked(self):
        self._rightDirectPortPairsItemListWidget.clearSelection()

    def listWR2Clicked(self):
        self._leftDirectPortPairsItemListWidget.clearSelection()

    def addHx(self):
        """
        Checks whether the inputs are in the correct range (0,100) and in order, and calls the function for creating a
        HeatExchanger on the respective side.

        Returns
        -------
        """
        try:
            _inputPercentageHeight = float(self.offsetLeI.text())
        except:
            self.parent.logger.warning('HX input height is not a number.')
            return

        try:
            _outputPercentageHeight = float(self.offsetLeO.text())
        except:
            self.parent.logger.warning('HX output height is not a number.')
            return

        if (self.minOffsetDistance()
                and _inputPercentageHeight > _outputPercentageHeight
                and self.offsetsInRange()):
            if self.rButton.isChecked():
                self.parent.logger.debug('Adding HX on righthand side.')
                self._addHxR()
            elif self.lButton.isChecked():
                self.parent.logger.debug('Adding HX on lefthand side.')
                self._addHxL()
            else:
                self.parent.logger.warning(
                    'No side selected for heat exchanger.')
                return
        else:
            msgb = QMessageBox()
            msgb.setText(
                "At least 20% of difference and larger top port than bottom port needed and valid range (0, 100)"
            )
            msgb.exec_()

    def minOffsetDistance(self):
        return abs(
            float(self.offsetLeI.text()) - float(self.offsetLeO.text())) >= 5

    def offsetsInRange(self):
        return (0 <= float(self.offsetLeI.text()) <= 100) and (0 <= float(
            self.offsetLeO.text()) <= 100)

    def _addHxL(self):
        self._addHeatExchanger(_sd.Side.LEFT)

    def _addHxR(self):
        self._addHeatExchanger(_sd.Side.RIGHT)

    def _addHeatExchanger(self, side: _sd.Side):
        name = self.hxNameLe.text()
        if not name:
            messageBox = QMessageBox()
            messageBox.setText(
                "Please specify the name of the heat exchanger that you want to add."
            )
            messageBox.exec_()
            return

        relativeInputHeight = float(self.offsetLeI.text()) / 100
        relativeOutputHeight = float(self.offsetLeO.text()) / 100

        trnsysId = self.parent.idGen.getTrnsysID()
        self.storage.addHeatExchanger(name, trnsysId, side,
                                      relativeInputHeight,
                                      relativeOutputHeight)

        self._loadHeatExchangers()

    def addPortPair(self):
        try:
            _inputPortPercentageHeight = float(self.manPortLeI.text())
        except:
            self.parent.logger.warning('Input port height is not a number.')
            return

        try:
            _outputPortPercentageHeight = float(self.manPortLeO.text())
        except:
            self.parent.logger.warning('Output port height is not a number.')
            return

        if max(_inputPortPercentageHeight,
               _outputPortPercentageHeight) >= 100 or min(
                   _inputPortPercentageHeight,
                   _outputPortPercentageHeight) <= 0:
            messageBox = QMessageBox()
            messageBox.setText(
                'Ports need to be on the tank, please make sure the port heights are within (0 %, 100 %).'
            )
            messageBox.exec_()
            return

        trnsysId = self.parent.idGen.getTrnsysID()

        if self.manlButton.isChecked():
            _pairSide = _sd.Side.LEFT
        elif self.manrButton.isChecked():
            _pairSide = _sd.Side.RIGHT
        else:
            self.parent.logger.warning('No side selected for port pair.')
            return

        self.storage.addDirectPortPair(
            trnsysId,
            _pairSide,
            _inputPortPercentageHeight / 100,
            _outputPortPercentageHeight / 100,
            self.storage.h,
        )

        self._loadDirectPortPairs()

    def removePortPairLeft(self):
        self._removeSelectedPortPairs(self._leftDirectPortPairsItemListWidget)

    def removePortPairRight(self):
        self._removeSelectedPortPairs(self._rightDirectPortPairsItemListWidget)

    def _removeSelectedPortPairs(self, directPortPairsListWidget):
        for selectedItem in directPortPairsListWidget.selectedItems():
            selectedDirectPortPair = selectedItem.data(_qtc.Qt.UserRole)

            self.storage.directPortPairs.remove(selectedDirectPortPair)

            row = directPortPairsListWidget.row(selectedItem)
            directPortPairsListWidget.takeItem(row)

            while len(selectedDirectPortPair.fromPort.connectionList) > 0:
                selectedDirectPortPair.fromPort.connectionList[0].deleteConn()

            while len(selectedDirectPortPair.toPort.connectionList) > 0:
                selectedDirectPortPair.toPort.connectionList[0].deleteConn()

            self.storage.inputs.remove(selectedDirectPortPair.fromPort)
            self.storage.outputs.remove(selectedDirectPortPair.toPort)

            self.storage.parent.scene().removeItem(
                selectedDirectPortPair.fromPort)
            self.storage.parent.scene().removeItem(
                selectedDirectPortPair.toPort)

    def removeHxL(self):
        self._removeSelectedHeatExchangers(
            self.leftHeatExchangersItemListWidget)

    def removeHxR(self):
        self._removeSelectedHeatExchangers(
            self.rightHeatExchangersItemListWidget)

    def _removeSelectedHeatExchangers(self, heatExchangersItemListWidget):
        for selectedItem in heatExchangersItemListWidget.selectedItems():
            heatExchanger = selectedItem.data(_qtc.Qt.UserRole)

            self.storage.heatExchangers.remove(heatExchanger)

            row = heatExchangersItemListWidget.row(selectedItem)
            heatExchangersItemListWidget.takeItem(row)

            while len(heatExchanger.port1.connectionList) > 0:
                heatExchanger.port1.connectionList[0].deleteConn()

            while len(heatExchanger.port2.connectionList) > 0:
                heatExchanger.port2.connectionList[0].deleteConn()

            self.storage.inputs.remove(heatExchanger.port1)
            self.storage.outputs.remove(heatExchanger.port2)

            self.storage.parent.scene().removeItem(heatExchanger.port1)
            self.storage.parent.scene().removeItem(heatExchanger.port2)
            self.storage.parent.scene().removeItem(heatExchanger)

    def modifyHx(self):
        """
        Modify Hx.
        """
        result = self._getFirstSelectedItemAndHeatExchanger()
        if not result:
            return
        selectedItem, heatExchanger = result

        modifyDialog = _mhd.ModifyRelativeHeightsDialog(
            heatExchanger.relativeInputHeight,
            heatExchanger.relativeOutputHeight)
        newHeights = modifyDialog.newRelativeHeights
        if not newHeights:
            return

        newInputHeight = newHeights.input if newHeights.input != "empty" else heatExchanger.relativeInputHeight
        newOutputHeight = newHeights.output if newHeights.output != "empty" else heatExchanger.relativeOutputHeight
        heatExchanger.setRelativeHeights(newInputHeight, newOutputHeight)

        listText = self._getHeatExchangerListItemText(heatExchanger)
        selectedItem.setText(listText)

    def _getFirstSelectedItemAndHeatExchanger(self):
        leftSelectedItems = self.leftHeatExchangersItemListWidget.selectedItems(
        )
        rightSelectedItems = self.rightHeatExchangersItemListWidget.selectedItems(
        )

        if leftSelectedItems:
            side = 0
            selectedItem = leftSelectedItems[0]
        elif rightSelectedItems:
            side = 2
            selectedItem = rightSelectedItems[0]
        else:
            return None

        name = selectedItem.text().split(",")[0]
        for heatExchanger in self.storage.heatExchangers:
            if heatExchanger.displayName == name and heatExchanger.sSide == side:
                return selectedItem, heatExchanger

        raise AssertionError(f"No heat exchanger with name {name} found.")

    def modifyPort(self):
        """
        Modify existing ports.
        """
        selectedItem = self._getFirstSelectedDirectPortPairListWidgetItem()
        if not selectedItem:
            return

        directPortPair: _dpp.DirectPortPair = selectedItem.data(
            _qtc.Qt.UserRole)

        dialogResult = _mhd.ModifyRelativeHeightsDialog(
            directPortPair.relativeInputHeight,
            directPortPair.relativeOutputHeight)
        newHeights = dialogResult.newRelativeHeights
        if not newHeights:
            return

        newRelativeInputHeight = newHeights.input if newHeights.input != "empty" else directPortPair.relativeInputHeight
        newRelativeOutputHeight = (newHeights.output
                                   if newHeights.output != "empty" else
                                   directPortPair.relativeOutputHeight)

        directPortPair.setRelativeHeights(newRelativeInputHeight,
                                          newRelativeOutputHeight,
                                          self.storage.h)

        newText = self._getDirectPortPairListItemText(directPortPair)
        selectedItem.setText(newText)

    def _getFirstSelectedDirectPortPairListWidgetItem(
        self, ) -> _tp.Optional[QListWidgetItem]:
        leftSelectedItems = self._leftDirectPortPairsItemListWidget.selectedItems(
        )
        if leftSelectedItems:
            return leftSelectedItems[0]

        rightSelectedItems = self._rightDirectPortPairsItemListWidget.selectedItems(
        )
        if rightSelectedItems:
            return rightSelectedItems[0]

        return None

    def incrSize(self):
        self._changeSize(self.HEIGHT_INCREMENT, self.WIDTH_INCREMENT)

    def decrSize(self):
        self._changeSize(-self.HEIGHT_INCREMENT, -self.WIDTH_INCREMENT)

    def _changeSize(self, deltaH, deltaW):
        self.storage.updatePortItemPositions(deltaH, deltaW)
        self.storage.h += deltaH
        self.storage.w += deltaW
        self.storage.updateHeatExchangersAfterTankSizeChange()
        self.storage.updateImage()

    def acceptedEdit(self):
        # print("Changing displayName")
        test = self.le.text()
        if self.le.text() == "":
            qmb = QMessageBox()
            qmb.setText("Please set a name for this storage tank.")
            qmb.setStandardButtons(QMessageBox.Ok)
            qmb.setDefaultButton(QMessageBox.Ok)
            qmb.exec()
            return
        self.storage.setName(self.le.text())
        self.close()

    def cancel(self):
        self.close()
Пример #25
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        #print('init')
        self.item_cnt = 0
        # self.canvas_cnt = 1

        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(610, 610)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget

        # 设置菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')
        set_pen_act = file_menu.addAction('设置画笔')
        reset_canvas_act = file_menu.addAction('重置画布')
        save_canvas_act = file_menu.addAction('保存画布')
        exit_act = file_menu.addAction('退出')
        draw_menu = menubar.addMenu('绘制')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        edit_menu = menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')

        # 连接信号和槽函数
        exit_act.triggered.connect(qApp.quit)
        set_pen_act.triggered.connect(self.set_pen)
        reset_canvas_act.triggered.connect(self.reset_canvas)
        save_canvas_act.triggered.connect(self.save_canvas)
        line_naive_act.triggered.connect(self.line_naive_action)
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)
        ellipse_act.triggered.connect(self.ellipse_action)
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)
        clip_cohen_sutherland_act.triggered.connect(self.clip_cohen_sutherland_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)
        self.list_widget.currentTextChanged.connect(self.canvas_widget.selection_changed)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(600, 600)
        self.setWindowTitle('CG 171860004')

    def get_id(self):
        self.item_cnt += 1
        _id = str(self.item_cnt)
        return _id
 
    def set_pen(self):
        red, ok1 = QInputDialog.getInt(self, "设置画笔颜色", "RED:")
        green, ok2 = QInputDialog.getInt(self, "设置画笔颜色", "GREEN:")
        blue, ok3 = QInputDialog.getInt(self, "设置画笔颜色", "BLUE:")
        if ok1 and ok2 and ok3:
            self.canvas_widget.set_color(QColor(red, green, blue))

    def reset_canvas(self):
        width, ok1 = QInputDialog.getInt(self, "重置画布", "width:")
        height, ok2 = QInputDialog.getInt(self, "重置画布", "height:")
        if width < 100:
            width = 100
        if width > 1000:
            width = 1000
        if height < 100:
            height = 100
        if height > 1000:
            height = 1000
        if ok1 and ok2:
            if self.canvas_widget.status != '':
                self.canvas_widget.finish_draw()
            self.list_widget.disconnect()
            self.list_widget.clear()
            self.scene.clear()
            self.list_widget.currentTextChanged.connect(self.canvas_widget.selection_changed)
            self.item_cnt = 0
            self.scene.setSceneRect(0, 0, width, height)
            self.canvas_widget.setFixedSize(width + 10, height + 10)

    def save_canvas(self):
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()
        img = self.canvas_widget.grab()
        name, ok = QInputDialog.getText(self, "保存画布", "文件名:")
        if ok:
            file_name = "output/"+name+".bmp"
            # self.canvas_cnt = self.canvas_cnt + 1
            img.save(file_name)

    def line_naive_action(self):
        self.canvas_widget.start_draw_line('Naive', str(self.item_cnt))
        self.statusBar().showMessage('Naive算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_dda_action(self):
        self.canvas_widget.start_draw_line('DDA', str(self.item_cnt))
        self.statusBar().showMessage('DDA算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        self.canvas_widget.start_draw_line('Bresenham', str(self.item_cnt))
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_dda_action(self):
        self.canvas_widget.start_draw_polygon('DDA', str(self.item_cnt))
        self.statusBar().showMessage('DDA算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_bresenham_action(self):
        self.canvas_widget.start_draw_polygon('Bresenham', str(self.item_cnt))
        self.statusBar().showMessage('Bresenham算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def ellipse_action(self):
        self.canvas_widget.start_draw_ellipse(str(self.item_cnt))
        self.statusBar().showMessage('中点圆生成算法绘制椭圆')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        self.canvas_widget.start_draw_curve('B_spline', str(self.item_cnt))
        self.statusBar().showMessage('B-spline算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        self.canvas_widget.start_draw_curve('Bezier', str(self.item_cnt))
        self.statusBar().showMessage('Bezier算法绘制曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def translate_action(self):
        self.canvas_widget.start_translate()
        self.statusBar().showMessage('平移')

    def rotate_action(self):
        self.canvas_widget.start_rotate()
        self.statusBar().showMessage('旋转')

    def scale_action(self):
        self.canvas_widget.start_scale()
        self.statusBar().showMessage('缩放')

    def clip_cohen_sutherland_action(self):
        self.canvas_widget.start_clip('Cohen-Sutherland')
        self.statusBar().showMessage('Cohen-Sutherland算法裁剪')
    
    def clip_liang_barsky_action(self):
        self.canvas_widget.start_clip('Liang-Barsky')
        self.statusBar().showMessage('Liang-Barsky算法裁剪')
Пример #26
0
class Window(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.mainWidget = QWidget()
        self.mainWidget.setMinimumSize(QtCore.QSize(640, 480))
        self.mainWidget.setWindowTitle("menoTulo")
        self.grid = QVBoxLayout()
        self.ui()

    def inputGrid(self):
        self.inputGrid = QHBoxLayout()
        self.otsikko = QLineEdit(self)
        self.summa = QLineEdit(self)
        self.otsikko.setPlaceholderText("Tulon/menon kuvaus...")
        self.summa.setPlaceholderText("Summa...")
        self.inputGrid.addWidget(self.otsikko)
        self.inputGrid.addWidget(self.summa)
        self.grid.addLayout(self.inputGrid)

    def nappiGrid(self):
        self.nappiGrid = QHBoxLayout()

        self.tuloButton = QPushButton("Lisää tulo", self)
        self.menoButton = QPushButton("Lisää meno", self)

        self.tuloButton.clicked.connect(self.addTulo)
        self.menoButton.clicked.connect(self.addMeno)

        self.nappiGrid.addWidget(self.tuloButton)
        self.nappiGrid.addWidget(self.menoButton)
        self.grid.addLayout(self.nappiGrid)

    def listaGrid(self):
        self.listaGrid = QHBoxLayout()
        self.tuloLista = QListWidget()
        self.menoLista = QListWidget()

        self.tuloLista.itemClicked.connect(self.deleteItem)
        self.menoLista.itemClicked.connect(self.deleteItem)

        self.listaGrid.addWidget(self.tuloLista)
        self.listaGrid.addWidget(self.menoLista)
        self.grid.addLayout(self.listaGrid)

    def totalGrid(self):
        self.totalGrid = QHBoxLayout()

        self.totalSum = 0
        self.totalMenot = 0
        self.totalTulot = 0

        self.tuloLabel = QLabel()
        self.sumLabel = QLabel()
        self.menoLabel = QLabel()
        self.clearButton = QPushButton("TYHJENNÄ KAIKKI", self)
        self.clearButton.clicked.connect(self.clearAll)

        self.totalGrid.addWidget(self.tuloLabel)
        self.totalGrid.addWidget(self.sumLabel)
        self.totalGrid.addWidget(self.menoLabel)
        self.totalGrid.addWidget(self.clearButton)

        self.tuloLabel.setText("TULOT:")
        self.sumLabel.setText("TOTAL:")
        self.menoLabel.setText("MENOT:")

        self.grid.addLayout(self.totalGrid)

    def ui(self):
        self.inputGrid()
        self.nappiGrid()
        self.listaGrid()
        self.totalGrid()
        self.mainWidget.setLayout(self.grid)
        self.mainWidget.show()

    def virhe(self):
        QMessageBox.about(self, "Virhe", "Syötä summaan vain numeroita!")

    def poistoVarmistus(self):
        vastaus = QMessageBox.question(self, "Poista valittu",
                                       "Poistetaanko varmasti?",
                                       QMessageBox.No | QMessageBox.Yes)
        if vastaus == QMessageBox.Yes:
            return True
        return False

    def tyhjennysVarmistus(self):
        vastaus = QMessageBox.question(self, "Tyhjennä kaikki",
                                       "Oletko varma?",
                                       QMessageBox.No | QMessageBox.Yes)
        if vastaus == QMessageBox.Yes:
            return True
        return False

    def clearAll(self):
        if self.tyhjennysVarmistus():
            self.totalSum = 0
            self.totalMenot = 0
            self.totalTulot = 0
            self.tuloLista.clear()
            self.menoLista.clear()
            self.tuloLabel.setText("TULOT:")
            self.sumLabel.setText("TOTAL:")
            self.menoLabel.setText("MENOT:")

    def deleteItem(self):
        if self.sender() == self.tuloLista:
            lista = self.tuloLista
        else:
            lista = self.menoLista

        if not lista.selectedItems():
            return

        if self.poistoVarmistus():
            for item in lista.selectedItems():
                poistoSumma = int(
                    lista.takeItem(lista.row(item)).text().split()[0])
                lista.takeItem(lista.row(item))
                if lista == self.tuloLista:
                    self.totalTulot -= poistoSumma
                else:
                    self.totalMenot -= poistoSumma
                self.updateTotal()

        self.tuloLista.clearSelection()
        self.menoLista.clearSelection()

    def updateTotal(self):
        self.tuloLabel.setText("TULOT: " + str(self.totalTulot))
        self.menoLabel.setText("MENOT: " + str(self.totalMenot))

        self.totalSum = self.totalTulot - self.totalMenot
        self.sumLabel.setText("TOTAL: " + str(self.totalSum))

    def addMeno(self):
        if not self.summa.text().isdigit():
            self.virhe()
            self.summa.clear()
        else:
            infoText = self.summa.text() + " " + self.otsikko.text()
            if infoText != " ":
                self.menoLista.addItem(infoText)
                self.totalSum -= int(self.summa.text())
                self.sumLabel.setText("TOTAL: " + str(self.totalSum))
                self.totalMenot += int(self.summa.text())
                self.menoLabel.setText("MENOT: " + str(self.totalMenot))
                self.summa.clear()
                self.otsikko.clear()
            else:
                pass

    def addTulo(self):
        if not self.summa.text().isdigit():
            self.virhe()
            self.summa.clear()
        else:
            infoText = self.summa.text() + " " + self.otsikko.text()
            if infoText != " ":
                self.tuloLista.addItem(infoText)
                self.totalSum += int(self.summa.text())
                self.sumLabel.setText("TOTAL: " + str(self.totalSum))
                self.totalTulot += int(self.summa.text())
                self.tuloLabel.setText("TULOT: " + str(self.totalTulot))
                self.summa.clear()
                self.otsikko.clear()
            else:
                pass
Пример #27
0
class CreateQuizWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.DEFAULT_BLOCK = (10, 100, [('Вопрос №1', ['Ответ №1',
                                                       'Ответ №2'], 0)])
        self.blocks = [self.DEFAULT_BLOCK]
        self.questions = self.blocks[0][2]
        self.cur_block = 0
        self.cur_question = -1
        self.initUI()

    def initUI(self):
        self.move(*COORDS)
        self.setWindowTitle('pyQuiz')

        self.title_edit = QLineEdit()
        self.title_edit.setPlaceholderText('Название викторины')
        self.title_edit.setAlignment(Qt.AlignCenter | Qt.AlignHCenter)

        self.prev_block_button = QPushButton()
        self.prev_block_button.setIcon(QIcon('assets/back.png'))
        self.prev_block_button.setFixedWidth(30)
        self.prev_block_button.setEnabled(False)
        self.prev_block_button.clicked.connect(self.prevBlock)

        self.next_block_button = QPushButton()
        self.next_block_button.setIcon(QIcon('assets/plus.png'))
        self.next_block_button.setFixedWidth(30)
        self.next_block_button.clicked.connect(self.nextBlock)

        self.delete_block_button = QPushButton()
        self.delete_block_button.setIcon(QIcon('assets/cross.png'))
        self.delete_block_button.setFixedWidth(30)
        self.delete_block_button.setEnabled(False)
        self.delete_block_button.clicked.connect(self.delBlock)

        self.block_name_label = QLabel('Блок №1')
        self.block_name_label.setAlignment(Qt.AlignCenter | Qt.AlignHCenter)

        self.block_time_limit = QLineEdit()
        self.block_time_limit.setPlaceholderText('Время на вопрос')

        self.block_points = QLineEdit()
        self.block_points.setPlaceholderText('Очки за вопрос')

        self.add_question_button = QPushButton()
        self.add_question_button.setIcon(QIcon('assets/plus.png'))
        self.add_question_button.clicked.connect(self.addQuestion)

        self.delete_question_button = QPushButton()
        self.delete_question_button.setIcon(QIcon('assets/cross.png'))
        self.delete_question_button.clicked.connect(self.deleteQuestion)

        self.questions_list = QListWidget()
        self.questions_list.setFixedWidth(150)
        self.questions_list.itemSelectionChanged.connect(self.switchQuestion)

        self.question_text_edit = QLineEdit()
        self.question_text_edit.setPlaceholderText('Текст вопроса')

        self.options_list = QListWidget()

        self.exit_button = QPushButton()
        self.exit_button.clicked.connect(self.exit)

        self.exit_button.setText('Назад')
        self.exit_button.setStyleSheet(
            'QPushButton{font-size:30px;text-align:center;background-color:#3C3F41;color:#BBBBBB;}'
        )

        self.save_button = QPushButton()
        self.save_button.setText('Сохранить')
        self.save_button.setStyleSheet(
            'QPushButton{font-size:30px;text-align:center;background-color:#3C3F41;color:#BBBBBB;}'
        )
        self.save_button.clicked.connect(self.save)

        self.add_option_button = QPushButton()
        self.add_option_button.setIcon(QIcon('assets/plus.png'))
        self.add_option_button.clicked.connect(self.addOption)

        self.delete_option_button = QPushButton()
        self.delete_option_button.setIcon(QIcon('assets/cross.png'))
        self.delete_option_button.clicked.connect(self.delOption)

        vbox = QVBoxLayout()

        menu_layout = QHBoxLayout()
        menu_layout.addWidget(self.prev_block_button)
        menu_layout.addWidget(self.block_name_label)
        menu_layout.addWidget(self.delete_block_button)
        menu_layout.addWidget(self.next_block_button)

        block_settings = QHBoxLayout()
        block_settings.addWidget(self.block_time_limit)
        block_settings.addWidget(self.block_points)

        main_layout = QHBoxLayout()

        block_table_layout = QVBoxLayout()
        block_table_layout.addWidget(self.questions_list)
        change_block_layout = QHBoxLayout()
        change_block_layout.addWidget(self.add_question_button)
        change_block_layout.addWidget(self.delete_question_button)
        block_table_layout.addLayout(change_block_layout)

        main_layout.addLayout(block_table_layout)
        question_layout = QVBoxLayout()

        question_layout.addWidget(self.question_text_edit)
        question_layout.addWidget(self.options_list)
        change_question_layout = QHBoxLayout()
        change_question_layout.addWidget(self.add_option_button)
        change_question_layout.addWidget(self.delete_option_button)
        question_layout.addLayout(change_question_layout)

        main_layout.addLayout(question_layout)

        footer_menu = QHBoxLayout()
        footer_menu.addWidget(self.exit_button)
        footer_menu.addWidget(self.save_button)

        vbox.addWidget(self.title_edit)
        vbox.addLayout(menu_layout)
        vbox.addLayout(block_settings)
        vbox.addLayout(main_layout)
        vbox.addLayout(footer_menu)

        self.restoreBlock()

        self.setLayout(vbox)
        self.setStyleSheet(QUIZ_STYLE_SHEET)
        self.setFixedSize(500, 500)

    def blockNavUpdate(self):
        if self.cur_block == len(self.blocks) - 1:
            self.next_block_button.setIcon(QIcon('assets/plus.png'))
        else:
            self.next_block_button.setIcon(QIcon('assets/next.png'))
        self.prev_block_button.setEnabled(self.cur_block > 0)
        self.next_block_button.setEnabled(
            self.cur_block < QUIZ_BLOCKS_NUM_RANGE.stop - 1)
        self.delete_block_button.setEnabled(len(self.blocks) > 1)
        self.block_name_label.setText(f'Блок № {self.cur_block + 1}')

    def showMsg(self, s, type=QMessageBox.Critical):
        msg = QMessageBox()
        msg.setIcon(type)
        msg.setText(s)
        msg.setWindowTitle('pyQuiz')
        msg.exec_()

    def saveBlock(self):
        if self.cur_question != -1:
            if not self.saveQuestion():
                return False
        time = self.block_time_limit.text()
        points = self.block_points.text()
        if not time.isnumeric():
            self.showMsg('Время на вопрос должно быть целым числом!')
            return False
        time = int(time)
        if time not in QUIZ_BLOCK_TIME_RANGE:
            self.showMsg(
                f'Время на вопрос должно быть не меньше {QUIZ_BLOCK_TIME_RANGE.start}, '
                f'но меньше {QUIZ_BLOCK_TIME_RANGE.stop}')
            return False
        if not points.isnumeric():
            self.showMsg('Кол-во очков за вопрос должно быть целым числом!')
            return False
        points = int(points)
        if points not in QUIZ_BLOCK_POINTS_RANGE:
            self.showMsg(
                f'Кол-во очков за вопрос должно быть не меньше {QUIZ_BLOCK_POINTS_RANGE.start}, '
                f'но меньше {QUIZ_BLOCK_POINTS_RANGE.stop}')
            return False
        if len(self.questions) not in QUIZ_QUESTIONS_NUM_RANGE:
            self.showMsg(
                f'Кол-во вопросов в блоке должно быть не меньше {QUIZ_QUESTIONS_NUM_RANGE.start}, '
                f'но меньше {QUIZ_QUESTIONS_NUM_RANGE.stop}')
            return False
        self.blocks[self.cur_block] = (time, points, self.questions)
        return True

    def restoreBlock(self):
        block = self.blocks[self.cur_block]
        self.block_time_limit.setText(str(block[0]))
        self.block_points.setText(str(block[1]))
        self.questions_list.clear()
        for question_text, options, right_option in block[2]:
            self.questions_list.addItem(question_text)
        self.questions = block[2][:]
        self.cur_question = -1
        self.questions_list.clearSelection()
        self.question_text_edit.setText('')
        self.options_list.clear()
        self.cur_question = -1

    def nextBlock(self):
        if not self.saveBlock():
            return
        self.cur_block += 1
        if self.cur_block == len(self.blocks):
            self.blocks.append(self.DEFAULT_BLOCK)
        self.blockNavUpdate()
        self.restoreBlock()

    def prevBlock(self):
        if not self.saveBlock():
            return
        self.cur_block -= 1
        self.blockNavUpdate()
        self.restoreBlock()

    def delBlock(self):
        self.blocks.pop(self.cur_block)
        if self.cur_block == len(self.blocks):
            self.cur_block -= 1
        self.blockNavUpdate()
        self.restoreBlock()

    def switchQuestion(self):
        if len(self.questions_list.selectedIndexes()) == 0:
            return
        if self.cur_question != -1:
            if not self.saveQuestion():
                self.questions_list.blockSignals(True)
                self.questions_list.clearSelection()
                self.questions_list.item(self.cur_question).setSelected(True)
                self.questions_list.blockSignals(False)
                return
        self.cur_question = self.questions_list.selectedIndexes()[0].row()
        self.restoreQuestion()

    def addQuestion(self):
        question_text, okBtnPressed = QInputDialog.getText(
            self, 'Создание вопроса', 'Введите текст вопроса')
        if not okBtnPressed:
            return
        if len(question_text) not in QUIZ_QUESTION_TEXT_LEN_RANGE:
            self.showMsg(
                f'Длина вопроса должна быть не меньше {QUIZ_QUESTION_TEXT_LEN_RANGE.start}, '
                f'но меньше {QUIZ_QUESTION_TEXT_LEN_RANGE.stop}',
                QMessageBox.Critical)
            return
        i = -1
        if len(self.questions_list.selectedIndexes()) > 0:
            i = self.questions_list.selectedIndexes()[0].row()
        i += 1
        self.questions.insert(i, (question_text, ['Ответ №1', 'Ответ №2'], 0))
        self.questions_list.insertItem(i, question_text)
        self.delete_question_button.setEnabled(True)

    def deleteQuestion(self):
        if len(self.questions_list.selectedIndexes()) == 0:
            return
        i = self.questions_list.selectedIndexes()[0].row()
        self.questions_list.takeItem(i)
        self.questions.pop()
        self.cur_question = -1

    def saveQuestion(self):
        question_text = self.question_text_edit.text()
        if len(question_text) not in QUIZ_QUESTION_TEXT_LEN_RANGE:
            self.showMsg(
                f'Длина текста вопроса должна быть не меньше {QUIZ_QUESTION_TEXT_LEN_RANGE.start}, '
                f'но меньше {QUIZ_QUESTION_TEXT_LEN_RANGE.stop}',
                QMessageBox.Critical)
            return False
        self.questions_list.item(self.cur_question).setText(question_text)
        options = []
        for i in range(len(self.options_list)):
            options.append(self.options_list.item(i).text())
        if len(options) not in QUIZ_OPTIONS_NUM_RANGE:
            self.showMsg(
                f'Кол-во ответов на вопрос должно быть не меньше {QUIZ_OPTIONS_NUM_RANGE.start}, '
                f'но меньше {QUIZ_OPTIONS_NUM_RANGE.stop}',
                QMessageBox.Critical)
            return False
        if len(self.options_list.selectedIndexes()) != 1:
            self.showMsg(f'Не выбран правильный ответ!', QMessageBox.Critical)
            return False
        right_answer = self.options_list.selectedIndexes()[0].row()
        self.questions[self.cur_question] = (question_text, options,
                                             right_answer)
        return True

    def restoreQuestion(self):
        question = self.questions[self.cur_question]
        self.question_text_edit.setText(question[0])
        self.options_list.clear()
        for option in question[1]:
            self.options_list.addItem(option)
        self.options_list.item(question[2]).setSelected(True)

    def addOption(self):
        option_text, okBtnPressed = QInputDialog.getText(
            self, 'Создание ответа', 'Введите текст ответа')
        if not okBtnPressed:
            return
        if len(option_text) not in QUIZ_OPTION_TEXT_LEN_RANGE:
            self.showMsg(
                f'Длина ответа должна быть не меньше {QUIZ_OPTION_TEXT_LEN_RANGE.start}, '
                f'но меньше {QUIZ_OPTION_TEXT_LEN_RANGE.stop}',
                QMessageBox.Critical)
            return
        self.options_list.addItem(option_text)

    def delOption(self):
        for index in self.options_list.selectedIndexes():
            self.options_list.takeItem(index.row())

    def save(self):
        if not self.saveBlock():
            return
        quiz_name = self.title_edit.text()
        if len(quiz_name) not in QUIZ_NAME_LEN_RANGE:
            self.showMsg(
                f'Длина названия викторины должна быть не меньше {QUIZ_NAME_LEN_RANGE.start}, '
                f'но меньше {QUIZ_NAME_LEN_RANGE.stop}')
            return
        quiz_json = {'name': quiz_name}
        cur = 0
        for time, pts, questions in self.blocks:
            for text, options, right_answer in questions:
                quiz_json[str(cur)] = {
                    'time': time,
                    'score': pts,
                    'question': text,
                    'answers': list(options),
                    'true': right_answer
                }
                cur += 1
        # QUIZ_SAVE_DIR
        file_name_preffix = secrets.token_hex(5)
        while os.path.isfile(os.path.join(QUIZ_SAVE_DIR, file_name_preffix)):
            file_name_preffix = secrets.token_hex(5)
        # https://stackoverflow.com/questions/18337407/saving-utf-8-texts-in-json-dumps-as-utf8-not-as-u-escape-sequence
        file_path = os.path.join(QUIZ_SAVE_DIR,
                                 quiz_name + '_' + file_name_preffix + '.json')
        with open(file_path, 'w', encoding='utf8') as json_file:
            json.dump(quiz_json,
                      json_file,
                      ensure_ascii=False,
                      sort_keys=True,
                      indent=4)
        self.exit()

    def exit(self):
        global COORDS
        COORDS = [self.x(), self.y()]
        self.create_game_window = QuizSelectionWindow()
        self.create_game_window.show()
        self.close()
Пример #28
0
class FontDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.__font_db = QFontDatabase()

        self.setWindowTitle(_("Select font"))

        layout = QVBoxLayout()

        content_layout = QHBoxLayout()

        font_list_layout = QVBoxLayout()

        font_list_layout.addWidget(QLabel(_("Font family:")))

        self.__font_search = UpDownPassingLineEdit()
        self.__font_search.textEdited.connect(self.__family_search_edited)

        font_list_layout.addWidget(self.__font_search)

        self.__font_list = QListWidget()
        self.__font_list.setFocusPolicy(Qt.NoFocus)

        for font in sorted(self.__font_db.families()):
            if self.__font_db.isSmoothlyScalable(font):
                self.__font_list.addItem(font)

        self.__font_list.currentTextChanged.connect(self.__family_changed)

        self.__font_search.destination_widget = self.__font_list

        font_list_layout.addWidget(self.__font_list)

        content_layout.addLayout(font_list_layout)

        style_layout = QVBoxLayout()
        style_layout.setAlignment(Qt.AlignCenter)

        self.__bold_widget = self.__create_style_button(
            "B", _("Bold"), QKeySequence.Bold, FontStyle.bold)
        style_layout.addWidget(self.__bold_widget)

        self.__italic_widget = self.__create_style_button(
            "I", _("Italic"), QKeySequence.Italic, FontStyle.italic)
        style_layout.addWidget(self.__italic_widget)

        self.__underline_widget = self.__create_style_button(
            "U", _("Underline"), QKeySequence.Underline, FontStyle.underline)
        style_layout.addWidget(self.__underline_widget)

        self.__strike_widget = self.__create_style_button(
            "S", _("Strike Out"), STRIKE_OUT, FontStyle.strike)
        style_layout.addWidget(self.__strike_widget)

        content_layout.addLayout(style_layout)

        size_layout = QVBoxLayout()
        size_layout.setAlignment(Qt.AlignHCenter)

        size_layout.addWidget(QLabel(_("Size (px):")))

        self.__size_edit = UpDownPassingLineEdit()
        self.__size_edit.textEdited.connect(self.__size_edited)
        self.__size_edit.setValidator(QIntValidator(5, 60))
        size_layout.addWidget(self.__size_edit)
        self.__size_edit.setSizePolicy(
            QSizePolicy.Preferred,
            self.__size_edit.sizePolicy().verticalPolicy())

        self.__size_slider = QSlider(Qt.Vertical)
        self.__size_slider.setFocusPolicy(Qt.NoFocus)
        self.__size_slider.setRange(5, 60)
        self.__size_slider.setTickInterval(5)
        self.__size_slider.setTickPosition(QSlider.TicksRight)
        self.__size_slider.valueChanged.connect(self.__size_changed)

        self.__size_edit.destination_widget = self.__size_slider

        size_layout.addWidget(self.__size_slider)

        content_layout.addLayout(size_layout)

        layout.addLayout(content_layout)

        self.__example = QLineEdit("AaBbYyZz")
        self.__example.setFixedHeight(80)
        layout.addWidget(self.__example)

        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        button_box.button(QDialogButtonBox.Ok).setText(_("Ok"))
        button_box.button(QDialogButtonBox.Cancel).setText(_("Cancel"))
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)

        layout.addWidget(button_box)
        self.setLayout(layout)

        self.__font = Fonts.default

    def __create_style_button(self, text, tooltip, keys, font_style):
        def toggled(value):
            self.__font = self.__font.change(font_style, value)
            self.__refresh_example_font()

        shortcut = QKeySequence(keys)
        widget = QPushButton(text)
        widget.setShortcut(shortcut)
        widget.setToolTip("{0} ({1})".format(tooltip, shortcut.toString()))
        font = widget.font()
        if font_style == FontStyle.bold:
            font.setBold(True)
        elif font_style == FontStyle.italic:
            font.setItalic(True)
        elif font_style == FontStyle.underline:
            font.setUnderline(True)
        elif font_style == FontStyle.strike:
            font.setStrikeOut(True)
        widget.setFont(font)
        widget.setCheckable(True)
        widget.toggled.connect(toggled)
        return widget

    @property
    def ufl_font(self):
        return self.__font

    @ufl_font.setter
    def ufl_font(self, value):
        self.__font = value

        for item in self.__font_list.findItems(value.family, Qt.MatchExactly):
            self.__font_list.setCurrentItem(item)
            break
        else:
            self.__font_list.clearSelection()

        self.__font_search.setText(value.family)

        self.__bold_widget.setChecked(FontStyle.bold in value.style)
        self.__italic_widget.setChecked(FontStyle.italic in value.style)
        self.__underline_widget.setChecked(FontStyle.underline in value.style)
        self.__strike_widget.setChecked(FontStyle.strike in value.style)

        self.__size_slider.setValue(value.size)
        self.__size_edit.setText(str(value.size))

        self.__refresh_example_font()

    def __refresh_example_font(self):
        qfont = QFont(self.__font.family)
        qfont.setPixelSize(self.__font.size)
        qfont.setBold(FontStyle.bold in self.__font.style)
        qfont.setItalic(FontStyle.italic in self.__font.style)
        qfont.setStrikeOut(FontStyle.strike in self.__font.style)
        qfont.setUnderline(FontStyle.underline in self.__font.style)

        self.__example.setFont(qfont)

    def __family_search_edited(self, name):
        selected_text = self.__font_list.currentItem().text()
        if selected_text.startswith(name):
            return

        for item in self.__font_list.findItems(name, Qt.MatchStartsWith):
            self.__font_list.setCurrentItem(item)
            break

    def __family_changed(self, value):
        if self.__font.family != value:
            if not self.__font_search.hasFocus():
                self.__font_search.setText(value)
            self.__font = self.__font.change_family(value)
            self.__refresh_example_font()

    def __size_edited(self, value):
        if not value or int(value) < 5:
            return
        int_value = int(value)
        if self.__font.size != int_value:
            self.__font = self.__font.change_size(int_value)

            self.__size_slider.setValue(int_value)

            self.__refresh_example_font()

    def __size_changed(self, value):
        if self.__font.size != value:
            if self.__size_edit.text() != str(value):
                self.__size_edit.setText(str(value))
                self.__size_edit.selectAll()
            self.__font = self.__font.change_size(value)
            self.__refresh_example_font()
Пример #29
0
class SessionViewer(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setMinimumSize(1100, 400)
        main_layout = QHBoxLayout()
        main_layout.setSpacing(5)
        self.setLayout(main_layout)

        list_column = QVBoxLayout()
        main_layout.addLayout(list_column, stretch=1)

        refresh_button = QPushButton('🔄 Refresh')
        refresh_button.setFont(cn.EMOJI_FONT)
        refresh_button.clicked.connect(self.refresh_list)
        list_column.addWidget(refresh_button)

        self.session_list = QListWidget()
        self.session_list.currentItemChanged.connect(self.show_session)
        list_column.addWidget(self.session_list)
        self.refresh_list()

        self.info_column = QVBoxLayout()
        main_layout.addLayout(self.info_column, stretch=1)

        self.info_column.addWidget(QLabel('Selected session info:'))

        self.session_info_table = QTableWidget()
        self.session_info_table.setColumnCount(2)
        self.session_info_table.horizontalHeader().setStretchLastSection(True)
        self.info_column.addWidget(self.session_info_table)

        self.info_column.addWidget(QLabel('Contained gestures:'))
        self.gesture_list = QListWidget()
        self.gesture_list.currentItemChanged.connect(self.show_gesture)
        self.info_column.addWidget(self.gesture_list)

        self.data_column = QVBoxLayout()
        self.data_column.setContentsMargins(0, 0, 0, 0)
        main_layout.addLayout(VerticalScrollableExtension(
            self.data_column,
            direction=QBoxLayout.TopToBottom,
            scrolled_spacing=10),
                              stretch=3)

        self.current_session_data = None
        self.current_gesture_names = None

    @staticmethod
    def load_session_data(session_name):
        file = f'data/gestures/{session_name}'
        with open(file, 'rb') as f:
            data = pickle.load(f)
            gesture_keys = [
                item for item in data if type(data[item]) == np.ndarray
            ]
        return data, sorted(gesture_keys, key=lambda x: str(x).zfill(5))

    @staticmethod
    def load_session_list():
        return sorted(
            filter(
                lambda x: x.startswith('s-') and x.count(cn.FILE_NAME_SEPARATOR
                                                         ) == 2,
                os.listdir(cn.DATA_FOLDER)))

    def refresh_list(self):
        self.session_list.clear()
        self.session_list.addItems(SessionViewer.load_session_list())

    def cleanup_shown_session(self):
        self.session_info_table.clear()
        self.gesture_list.clearSelection()
        self.gesture_list.clear()
        for i in range(self.data_column.count()):
            self.data_column.itemAt(i).widget().plot_data(None)

    def show_session(self, current_item):
        if not current_item:
            return
        self.cleanup_shown_session()
        session_name = current_item.text()
        self.current_session_data, self.current_gesture_names = SessionViewer.load_session_data(
            session_name)

        self.session_info_table.setRowCount(2 +
                                            len(self.current_session_data) -
                                            len(self.current_gesture_names))
        row = 0
        for info in self.current_session_data:
            if info in self.current_gesture_names:
                continue
            self.session_info_table.setItem(row, 0, QTableWidgetItem(info))
            self.session_info_table.setItem(
                row, 1, QTableWidgetItem(str(self.current_session_data[info])))
            row += 1
        self.session_info_table.setItem(row, 0, QTableWidgetItem('Gestures'))
        self.session_info_table.setItem(
            row, 1, QTableWidgetItem(str(len(self.current_gesture_names))))
        self.session_info_table.setItem(row + 1, 0,
                                        QTableWidgetItem('Instances'))
        self.session_info_table.setItem(
            row + 1, 1,
            QTableWidgetItem(
                str(
                    sum(
                        map(lambda name: len(self.current_session_data[name]),
                            self.current_gesture_names)))))

        self.gesture_list.addItems(
            map(
                lambda name:
                f'{name} ({len(self.current_session_data[name])} inst.)',
                self.current_gesture_names))

    def show_gesture(self):
        current_gesture_data = self.current_session_data[
            self.current_gesture_names[self.gesture_list.currentIndex().row()]]

        new_count = len(current_gesture_data)
        old_count = self.data_column.count()

        for i in range(old_count, new_count):
            self.data_column.addWidget(StaticSignalWidget())

        for i in range(new_count, old_count):
            self.data_column.itemAt(i).widget().plot_data(None)

        for i, instance in enumerate(current_gesture_data):
            # We use a function here, to create a temporary scope for index & data
            w = self.data_column.itemAt(i).widget()
            w.plot_data(instance)
Пример #30
0
class MainWindow(QMainWindow):
    """
    主窗口类
    """
    def __init__(self):
        super().__init__()
        self.item_cnt = 0

        # 使用QListWidget来记录已有的图元,并用于选择图元。注:这是图元选择的简单实现方法,更好的实现是在画布中直接用鼠标选择图元
        self.list_widget = QListWidget(self)
        self.list_widget.setMinimumWidth(200)

        # 使用QGraphicsView作为画布
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 600, 600)
        self.canvas_widget = MyCanvas(self.scene, self)
        self.canvas_widget.setFixedSize(600 + 2, 600 + 2)
        self.canvas_widget.main_window = self
        self.canvas_widget.list_widget = self.list_widget
        self.canvas_widget.temp_id = self.get_id()

        # 设置菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')
        # set_pen_act = file_menu.addAction('设置画笔')
        set_pen_act = file_menu.addMenu('设置画笔')
        set_pen_color_act = set_pen_act.addAction('设置颜色')
        set_pen_width_act = set_pen_act.addAction('设置粗细')
        reset_canvas_act = file_menu.addAction('重置画布')
        save_canvas_act = file_menu.addAction('保存画布')
        exit_act = file_menu.addAction('退出')
        draw_menu = menubar.addMenu('绘制')
        pencil_act = draw_menu.addAction('铅笔')
        line_menu = draw_menu.addMenu('线段')
        line_naive_act = line_menu.addAction('Naive')
        line_dda_act = line_menu.addAction('DDA')
        line_bresenham_act = line_menu.addAction('Bresenham')
        polygon_menu = draw_menu.addMenu('多边形')
        polygon_dda_act = polygon_menu.addAction('DDA')
        polygon_bresenham_act = polygon_menu.addAction('Bresenham')
        ellipse_act = draw_menu.addAction('椭圆')
        curve_menu = draw_menu.addMenu('曲线')
        curve_bezier_act = curve_menu.addAction('Bezier')
        curve_b_spline_act = curve_menu.addAction('B-spline')
        polyline_menu = draw_menu.addMenu('折线')
        polyline_dda_act = polyline_menu.addAction('DDA')
        polyline_bresenham_act = polyline_menu.addAction('Bresenham')
        edit_menu = menubar.addMenu('编辑')
        translate_act = edit_menu.addAction('平移')
        rotate_act = edit_menu.addAction('旋转')
        scale_act = edit_menu.addAction('缩放')
        clip_menu = edit_menu.addMenu('裁剪')
        clip_cohen_sutherland_act = clip_menu.addAction('Cohen-Sutherland')
        clip_liang_barsky_act = clip_menu.addAction('Liang-Barsky')
        copy_act = edit_menu.addAction('复制粘贴')
        delete_act = edit_menu.addAction('删除')
        choose_act = menubar.addAction('鼠标选中')
        undo_act = menubar.addAction('撤销')

        # 连接信号和槽函数 mark
        # set_pen_act.triggered.connect(self.set_pen_color_action)
        set_pen_color_act.triggered.connect(self.set_pen_color_action)
        set_pen_width_act.triggered.connect(self.set_pen_width_action)
        reset_canvas_act.triggered.connect(self.reset_canvas_action)
        save_canvas_act.triggered.connect(self.save_canvas_action)
        undo_act.triggered.connect(self.undo_action)
        exit_act.triggered.connect(qApp.quit)
        pencil_act.triggered.connect(self.pencil_action)
        line_naive_act.triggered.connect(self.line_naive_action)
        line_dda_act.triggered.connect(self.line_dda_action)
        line_bresenham_act.triggered.connect(self.line_bresenham_action)
        polygon_dda_act.triggered.connect(self.polygon_dda_action)
        polygon_bresenham_act.triggered.connect(self.polygon_bresenham_action)
        polyline_dda_act.triggered.connect(self.polyline_dda_action)
        polyline_bresenham_act.triggered.connect(
            self.polyline_bresenham_action)
        ellipse_act.triggered.connect(self.ellipse_action)
        curve_bezier_act.triggered.connect(self.curve_bezier_action)
        curve_b_spline_act.triggered.connect(self.curve_b_spline_action)
        translate_act.triggered.connect(self.translate_action)
        rotate_act.triggered.connect(self.rotate_action)
        scale_act.triggered.connect(self.scale_action)
        copy_act.triggered.connect(self.copy_action)
        delete_act.triggered.connect(self.delete_action)
        clip_liang_barsky_act.triggered.connect(self.clip_liang_barsky_action)
        clip_cohen_sutherland_act.triggered.connect(
            self.clip_cohen_sutherland_action)
        choose_act.triggered.connect(self.choose_action)
        self.list_widget.currentTextChanged.connect(
            self.canvas_widget.selection_changed)

        # 设置主窗口的布局
        self.hbox_layout = QHBoxLayout()
        self.hbox_layout.addWidget(self.canvas_widget)
        self.hbox_layout.addWidget(self.list_widget, stretch=1)
        self.central_widget = QWidget()
        self.central_widget.setLayout(self.hbox_layout)
        self.setCentralWidget(self.central_widget)
        self.statusBar().showMessage('空闲')
        self.resize(600, 600)
        self.setWindowTitle('XY\'s CG Demo')

    def get_id(self):
        _id = str(self.item_cnt)
        self.item_cnt += 1
        return _id

    def delete_id(self):
        self.item_cnt -= 1

    def undo_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_undo()
        self.statusBar().showMessage('撤销')

    def set_pen_color_action(self):
        if self.canvas_widget.drawing != 0:
            return
        color = QColorDialog.getColor()
        if color.isValid:  # 通过isValid()可以判断用户选择的颜色是否有效,若用户选择取消,isValid()将返回false
            self.canvas_widget.pen_color = color

    def set_pen_width_action(self):
        if self.canvas_widget.drawing != 0:
            return
        num1, ok1 = QInputDialog.getInt(self, '设置画笔宽度', '输入您的宽度(1~10)', 1, 1,
                                        10, 1)
        if ok1:  # 通过isValid()可以判断用户选择的颜色是否有效,若用户选择取消,isValid()将返回false
            self.canvas_widget.pen_width = num1

    def choose_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.status = ''

    def reset_canvas_action(self):
        if self.canvas_widget.drawing != 0:
            return
        num1, ok1 = QInputDialog.getInt(self, '获取宽度', '输入您的宽度(100~1000)', 600,
                                        100, 1000, 1)
        if ok1:
            num2, ok2 = QInputDialog.getInt(self, '获取高度', '输入您的高度(100~1000)',
                                            600, 100, 1000, 1)
        if ok1 and ok2:
            # 清空画布
            self.list_widget.clear()
            self.item_cnt = 0
            self.canvas_widget.action_stack = []
            self.canvas_widget.temp_id = self.get_id()
            # 更改画布大小
            self.scene = QGraphicsScene(self)
            self.scene.setSceneRect(0, 0, num1, num2)
            self.canvas_widget.setScene(self.scene)
            self.canvas_widget.setFixedSize(num1 + 2, num2 + 2)

    def save_canvas_action(self):
        if self.canvas_widget.drawing != 0:
            return
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filename, ok = QFileDialog.getSaveFileName(
            self,
            "QFileDialog.getSaveFileName()",
            "",
            "Pictures (*.bmp)",
            options=options)
        if ok:
            filename = filename + ".bmp"
            # print(filename)
            pix_map = self.canvas_widget.grab(
                self.canvas_widget.sceneRect().toRect())
            pix_map.save(filename)

    def line_naive_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_line('Naive')
        self.statusBar().showMessage('Naive算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_dda_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_line('DDA')
        self.statusBar().showMessage('DDA算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def line_bresenham_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_line('Bresenham')
        self.statusBar().showMessage('Bresenham算法绘制线段')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_dda_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_polygon('DDA')
        self.statusBar().showMessage('DDA算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polygon_bresenham_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_polygon('Bresenham')
        self.statusBar().showMessage('Bresenham算法绘制多边形')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polyline_dda_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_polyline('DDA')
        self.statusBar().showMessage('DDA算法绘制折线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def polyline_bresenham_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_polyline('Bresenham')
        self.statusBar().showMessage('Bresenham算法绘制折线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def pencil_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_pencil('Pencil')
        self.statusBar().showMessage('铅笔')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def ellipse_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_ellipse('center')
        self.statusBar().showMessage('中心圆生成算法绘制椭圆')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_bezier_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_curve('Bezier')
        self.statusBar().showMessage('绘制Bezier曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def curve_b_spline_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_draw_curve('B-spline')
        self.statusBar().showMessage('绘制B-spline曲线')
        self.list_widget.clearSelection()
        self.canvas_widget.clear_selection()

    def copy_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_copy()
        self.statusBar().showMessage('复制粘贴')

    def translate_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_translate('平移')
        self.statusBar().showMessage('平移')

    def rotate_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_rotate('旋转')
        self.statusBar().showMessage('旋转')

    def scale_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_scale('缩放')
        self.statusBar().showMessage('缩放')

    def delete_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_delete()
        self.statusBar().showMessage('删除')

    def clip_liang_barsky_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_clip('Liang-Barsky')
        self.statusBar().showMessage('线段裁剪')

    def clip_cohen_sutherland_action(self):
        if self.canvas_widget.drawing != 0:
            return
        self.canvas_widget.start_clip('Cohen-Sutherland')
        self.statusBar().showMessage('线段裁剪')