Exemplo n.º 1
0
def vertical_resize_table_view_to_contents(table_view: QtWidgets.QTableView):
    row_total_height = 0

    count = table_view.verticalHeader().count()
    for i in range(0, count):
        if not table_view.verticalHeader().isSectionHidden(i):
            row_total_height += table_view.verticalHeader().sectionSize(i)
    if not table_view.horizontalScrollBar().isHidden():
        row_total_height += table_view.horizontalScrollBar().height()

    if not table_view.horizontalHeader().isHidden():
        row_total_height += table_view.horizontalHeader().height()
    table_view.setMinimumHeight(row_total_height)
Exemplo n.º 2
0
class SideDock(QDockWidget):
    """
    Side Dock/Panel, named "Navy Base Overview", displays all important data of the user.
        This is the first coded QWidget of WGViewer (even before LoginForm).
    """
    sig_resized = pyqtSignal()
    sig_closed = pyqtSignal()

    def __init__(self, parent, realrun: bool):
        super(SideDock, self).__init__(parent)
        self.is_realrun = realrun

        _, self.user_screen_h = wgv_utils.get_user_resolution()
        self.qsettings = QSettings(wgv_data.get_qsettings_file(), QSettings.IniFormat)
        if self.qsettings.contains(QKEYS.EXP_AUTO) and self.qsettings.value(QKEYS.EXP_AUTO, type=bool):
            logger.debug("Auto expedition is on")
            self.is_exp_auto = True
        else:
            logger.debug("Auto expedition is off")
            self.is_exp_auto = False

        self.equipment_names = wgv_data.get_shipEquipmnt()
        self.ship_names = wgv_data.get_processed_userShipVo()

        # index 0 for daily, 1 for weekly, 2+ for tasks/events
        self.task_counter_desc_labels = []
        self.task_counter_labels = []
        self.task_counter_timers = []
        self.task_counters = []

        self.name_layout_widget = QWidget(self)
        self.name_layout = QHBoxLayout(self.name_layout_widget)
        self.name_label = QLabel(self.name_layout_widget)
        self.lvl_label = QLabel(self.name_layout_widget)
        self.ship_count_label = QLabel(self.name_layout_widget)
        self.equip_count_label = QLabel(self.name_layout_widget)
        self.collect_count_label = QLabel(self.name_layout_widget)

        self.sign_widget = QLineEdit(self)
        self.table_model = ResourceTableModel()
        self.table_view = QTableView(self)
        self.bath_list_view = BathListView()
        self.bath_list_view_widget = QWidget(self)
        self.bath_list_view_layout = QVBoxLayout(self.bath_list_view_widget)
        self.triple_list_view_widget = QWidget(self)
        self.triple_list_view = QHBoxLayout(self.triple_list_view_widget)
        self.build_list_view = BuildListView()
        self.dev_list_view = DevListView()
        self.exp_list_view = ExpListView(parent.main_tabs)
        self.task_list_view = TaskListView()
        self.task_panel_widget = QWidget(self)
        self.task_panel_view = QHBoxLayout(self.task_panel_widget)
        self.countdowns_layout_widget = QWidget(self)
        self.countdowns_layout = QVBoxLayout(self.countdowns_layout_widget)

        self.sig_resized.connect(self.update_geometry)
        self.sig_closed.connect(parent.on_dock_closed)

        self._init_ui()
        self.set_data()

    def set_data(self) -> None:
        d = wgv_data.get_api_initGame()
        self.on_received_lists(d)
        self.on_received_resource(d)
        self.on_received_name(d)
        self.on_received_tasks(d)

    def _init_ui(self) -> None:
        self.setFloating(False)
        self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.setMinimumWidth(int(0.4 * self.user_screen_h))
        self.setWindowTitle("Navy Base Overview")

        self._init_name_info()
        self._init_sign_info()
        self._init_resource_info()
        self._init_bath_info()
        self._init_triple_list()
        self._init_task_panel()

    def _init_name_info(self) -> None:
        self.name_layout.setContentsMargins(0, 0, 0, 0)

        self.name_layout.addWidget(self.name_label)
        self.name_layout.addWidget(self.lvl_label)
        self.name_layout.addWidget(self.ship_count_label)
        self.name_layout.addWidget(self.equip_count_label)
        self.name_layout.addWidget(self.collect_count_label)

    def _init_sign_info(self) -> None:
        icon_path = get_data_path('assets/icons/sign_16.png')
        self.sign_widget.addAction(QIcon(icon_path), QLineEdit.LeadingPosition)

    def _init_resource_info(self) -> None:
        self.table_view.setModel(self.table_model)
        x = 0.03 * self.user_screen_h
        self.table_view.setIconSize(QSize(x, x))
        self.table_view.verticalHeader().hide()
        self.table_view.horizontalHeader().hide()
        self.table_view.setShowGrid(False)
        self.table_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table_view.setFocusPolicy(Qt.NoFocus)
        self.table_view.setSelectionMode(QAbstractItemView.NoSelection)
        self.table_view.horizontalScrollBar().setEnabled(False)
        self.table_view.verticalScrollBar().setEnabled(False)

    def _init_bath_info(self) -> None:
        self.bath_list_view_layout.setContentsMargins(0, 0, 0, 0)
        self.bath_list_view_layout.addWidget(self.bath_list_view)

    def _init_triple_list(self) -> None:
        self.triple_list_view.setContentsMargins(0, 0, 0, 0)
        self.triple_list_view.addWidget(self.build_list_view)
        self.triple_list_view.addWidget(self.dev_list_view)
        self.triple_list_view.addWidget(self.exp_list_view)

    def _init_task_panel(self) -> None:
        self.task_panel_view.setContentsMargins(0, 0, 0, 0)
        self._init_countdowns()
        self.task_panel_view.addWidget(self.task_list_view)
        self.task_panel_view.addWidget(self.countdowns_layout_widget)

    def _init_countdowns(self) -> None:
        # TODO? design problem now the most suitable count is 4, 5 would be max
        #   although MoeFantasy opens mostly 1 event at a time, rarely 2.
        self.countdowns_layout.setContentsMargins(0, 0, 0, 0)

        l1 = QLabel(self.countdowns_layout_widget)
        l1.setToolTip("Refreshing daily at 0300 UTC+8")  # Intel' server also use CN time
        l1.setText("Next daily:")
        l1.adjustSize()
        self.task_counter_desc_labels.append(l1)

        l2 = QLabel(self.countdowns_layout_widget)
        l2.setText("Next weekly:")
        l2.setToolTip("Refreshing weekly at 0400 UTC+8 or New Year")
        l2.adjustSize()
        self.task_counter_desc_labels.append(l2)

        self.task_counter_labels.append(QLabel(self.countdowns_layout_widget))
        self.task_counter_labels.append(QLabel(self.countdowns_layout_widget))

        self.countdowns_layout.addWidget(l1)
        self.countdowns_layout.addWidget(self.task_counter_labels[0])
        self.countdowns_layout.addWidget(l2)
        self.countdowns_layout.addWidget(self.task_counter_labels[1])

        _, _, d_counter, w_counter = get_tasks_countdowns()
        self.task_counters.append(d_counter)
        self.task_counters.append(w_counter)

        self._init_task_counters()

    # ================================
    # Getter / Setter
    # ================================

    def add_task_countdown(self, text: str, _time: int, idx: int) -> None:
        l1 = QLabel(self.countdowns_layout_widget)
        l1.setText(text)
        l1.adjustSize()
        self.task_counter_desc_labels.append(l1)
        self.countdowns_layout.addWidget(l1)

        l2 = QLabel(self.countdowns_layout_widget)
        self.task_counter_labels.append(l2)
        self.task_counters.append(_time)
        self.countdowns_layout.addWidget(l2)
        self.start_new_timer(self.task_counters, self.task_counter_labels, self.task_counter_timers, idx)

    def get_ship_name(self, _id):
        return self.ship_names[str(_id)]['Name']

    def get_equip_name(self, cid: int) -> str:
        return next((i for i in self.equipment_names if i['cid'] == cid), {'title': '?'})['title']

    @staticmethod
    def get_ship_type(_id: int) -> str:
        return wgv_utils.get_build_type(_id)

    @staticmethod
    def _remove_widget(parent, widget: [QLayout, QWidget]) -> None:
        logger.warning("Deleting widget")
        parent.removeWidget(widget)
        widget.deleteLater()
        widget = None
        return

    def get_exp_list_view(self) -> ExpListView:
        return self.exp_list_view

    # ================================
    # Timer Related
    # ================================

    def count_down(self, counters: list, labels: list, timers: list, idx: int) -> None:
        # TODO? refactor; each list view has its own countdown method?
        counters[idx] -= 1
        if counters[idx] > 0:
            pass
        else:
            if counters == self.task_counters:
                if idx < 2:
                    # refreshing daily/weekly timers
                    _, _, d, w = get_tasks_countdowns()
                    counters[0] = d
                    counters[1] = w
                else:
                    counters[idx] = 0
                    timers[idx].stop()
                    self._remove_widget(self.countdowns_layout, labels[idx])
                    self._remove_widget(self.countdowns_layout, self.task_counter_desc_labels[idx])
                    return
            elif counters == self.bath_list_view.get_counters():
                counters[idx] = 0
                timers[idx].stop()
                self.bath_list_view.update_item(idx, 0, "Repairing Dock Unused")
                self.bath_list_view.update_item(idx, 1, "--:--:--")
            elif counters == self.exp_list_view.get_counters():
                counters[idx] = 0
                timers[idx].stop()
                # To avoid "Idling" (uninitialized) issue
                labels[idx].setText(str(timedelta(seconds=counters[idx])))
                if self.is_realrun and self.is_exp_auto:
                    self.exp_list_view.auto_restart(idx)
                else:
                    # otherwise will cause problem
                    pass
            else:
                counters[idx] = 0
                timers[idx].stop()
        labels[idx].setText(str(timedelta(seconds=counters[idx])))

    def start_new_timer(self, counters: list, labels: list, timers: list, idx: int) -> None:
        """
        Creates a QTimer() object and auto connects to 1 sec count down.
        Then auto start
        """
        tr = QTimer()
        tr.setInterval(1000)
        tr.timeout.connect(lambda: self.count_down(counters, labels, timers, idx))
        if counters == self.task_counters:
            timers.append(tr)
        else:
            timers[idx] = tr
        tr.start()

    def _init_task_counters(self) -> None:
        self.start_new_timer(self.task_counters, self.task_counter_labels, self.task_counter_timers, 0)
        self.start_new_timer(self.task_counters, self.task_counter_labels, self.task_counter_timers, 1)

    def _process_timer_data(self, _data, view, func, item_id, counters, labels, timers) -> None:
        for i, v in enumerate(_data):
            if v["locked"] == 0:
                if "endTime" in v:
                    _left_time = _calc_left_time(v["endTime"])
                    counters[i] = _left_time
                    self.start_new_timer(counters, labels, timers, i)
                    val1 = func(v[item_id])
                    view.update_item(i, 0, val1)
                else:
                    view.update_item(i, 0, "Unused")
                    view.update_item(i, 1, "--:--:--")
            else:
                pass

    # ================================
    # Signals
    # ================================

    @pyqtSlot(dict)
    def on_received_resource(self, data: dict) -> None:
        if data is not None:
            def _get_item_by_id(item_id: int) -> int:
                return next((i for i in x if i["itemCid"] == item_id), {"num": 0})["num"]

            u = data["userVo"]
            x = data["packageVo"]
            self.table_model.update_fuel(u["oil"])
            self.table_model.update_ammo(u["ammo"])
            self.table_model.update_steel(u["steel"])
            self.table_model.update_bauxite(u["aluminium"])
            self.table_model.update_gold(u["gold"])
            self.table_model.update_repair(_get_item_by_id(541))
            self.table_model.update_build(_get_item_by_id(141))
            self.table_model.update_bp_construct(_get_item_by_id(241))
            self.table_model.update_bp_dev(_get_item_by_id(741))
            self.table_model.update_revive(_get_item_by_id(66641))
            self.table_model.update_DD(_get_item_by_id(10441))
            self.table_model.update_CA(_get_item_by_id(10341))
            self.table_model.update_BB(_get_item_by_id(10241))
            self.table_model.update_CV(_get_item_by_id(10141))
            self.table_model.update_SS(_get_item_by_id(10541))

            self.table_model.write_csv()

    @pyqtSlot(dict)
    def update_lvl_label(self, x: dict) -> None:
        # userLevelVo
        if x is not None:
            self.lvl_label.setText("Lv. " + str(x["level"]))
            lvl_tooltip = str(x["exp"]) + " / " + str(x["nextLevelExpNeed"])
            self.lvl_label.setToolTip(lvl_tooltip)

    @pyqtSlot(dict)
    def on_received_name(self, data: dict) -> None:
        if data is not None:
            x = data["userVo"]["detailInfo"]
            self.name_label.setText(x["username"])
            name_tooltip = "resource soft cap = " + str(data["userVo"]["resourcesTops"][0])
            self.name_label.setToolTip(name_tooltip)

            self.update_lvl_label(x)

            ship_icon = get_data_path('assets/icons/ship_16.png')
            ship_str = f"<html><img src='{ship_icon}'></html> " + str(x["shipNum"]) + " / " + str(x["shipNumTop"])
            self.ship_count_label.setText(ship_str)

            equip_icon = get_data_path('assets/icons/equip_16.png')
            equip_str = f"<html><img src='{equip_icon}'></html> " + str(x["equipmentNum"]) + " / " + str(x["equipmentNumTop"])
            self.equip_count_label.setText(equip_str)

            collect_icon = get_data_path('assets/icons/collect_16.png')
            collect_str = f"<html><img src='{collect_icon}'></html> " + str(len(data["unlockShip"])) + " / " + str(x["basicShipNum"])
            self.collect_count_label.setText(collect_str)

            self.sign_widget.setText(data["friendVo"]["sign"])

    def update_one_expedition(self, data: dict) -> None:
        # Input = pveExploreVo['levels'][_idx]
        _idx = int(data['fleetId'])-5
        _exp_counters = self.exp_list_view.get_counters()
        _exp_counters[_idx] = _calc_left_time(data["endTime"])
        self.start_new_timer(_exp_counters, self.exp_list_view.get_counter_labels(), self.exp_list_view.get_counter_timers(), _idx)
        n = "Fleet #" + data["fleetId"] + "   " + data["exploreId"].replace("000", "-")
        self.exp_list_view.update_item(_idx, 0, n)

    def cancel_one_expedition(self, fleet_idx: int) -> None:
        self.exp_list_view.update_item(fleet_idx, 0, EXP_LABEL_L)
        self.exp_list_view.update_item(fleet_idx, 1, EXP_LABEL_R)
        self.exp_list_view.get_counters()[fleet_idx] = 0
        self.exp_list_view.get_counter_timers()[fleet_idx].stop()

    def update_expeditions(self, data: dict) -> None:
        if data is not None:
            p = sorted(data["levels"], key=lambda x: int(x['fleetId']), reverse=False)
            for _, val in enumerate(p):
                self.update_one_expedition(val)

    @pyqtSlot(dict)
    def on_received_lists(self, data: dict) -> None:
        if data is not None:
            self._process_timer_data(data["repairDockVo"], self.bath_list_view, self.get_ship_name, "shipId",
                                     self.bath_list_view.get_counters(), self.bath_list_view.get_counter_labels(), self.bath_list_view.get_counter_timers())

            self._process_timer_data(data["dockVo"], self.build_list_view, self.get_ship_type, "shipType",
                                     self.build_list_view.get_counters(), self.build_list_view.get_counter_labels(), self.build_list_view.get_counter_timers())

            self._process_timer_data(data["equipmentDockVo"], self.dev_list_view, self.get_equip_name, "equipmentCid",
                                     self.dev_list_view.get_counters(), self.bath_list_view.get_counter_labels(), self.dev_list_view.get_counter_timers())

            self.update_expeditions(data["pveExploreVo"])

    @pyqtSlot(dict)
    def on_received_tasks(self, data: dict) -> None:
        if data is not None:
            t = data["taskVo"]
            for i in t:
                stat = str(i["condition"][0]["finishedAmount"]) + " / " + str(i["condition"][0]["totalAmount"])
                desc = wgv_utils.clear_desc(i["desc"])
                if '#' in desc:
                    # TODO: (lowest priority) how to find `#s10030711#n` ? looks like not the same ID in docks
                    desc = re.sub(r'\[[^]]*\]', i["title"], desc)
                else:
                    pass
                if i['end_time'] != "":
                    desc += "\nEvent End On: " + i['end_time']
                    lim_flag = True
                else:
                    lim_flag = False
                prefix = TASK_TYPE[i['type']]
                title = f"{prefix}\t{i['title']}"
                self.task_list_view.add_item(title, stat, desc, lim_flag)

            m = data["marketingData"]["activeList"]
            for i in m:
                self.add_task_countdown(i["title"], i["left_time"], len(self.task_counters))

    # ================================
    # Events
    # ================================

    def resizeEvent(self, event: QResizeEvent) -> None:
        # overriding resizeEvent() method
        self.sig_resized.emit()
        return super(SideDock, self).resizeEvent(event)

    def closeEvent(self, event: QCloseEvent) -> None:
        cb = QCheckBox('show on start-up')
        if self.qsettings.contains(QKEYS.UI_SIDEDOCK) is True:
            cb.setChecked(self.qsettings.value(QKEYS.UI_SIDEDOCK, type=bool) is True)
        else:
            pass
        box = QMessageBox(QMessageBox.Question, "INFO", "Do you want to close side dock?\n(Can re-open in View menu)",
                          QMessageBox.Yes | QMessageBox.No, self)

        box.setStyleSheet(wgv_utils.get_color_scheme())
        box.setDefaultButton(QMessageBox.No)
        box.setCheckBox(cb)

        if box.exec() == QMessageBox.Yes:
            event.accept()
            self.sig_closed.emit()
        else:
            event.ignore()
        self.qsettings.setValue(QKEYS.UI_SIDEDOCK, cb.isChecked())

    def update_geometry(self) -> None:
        y = int(0.03 * self.user_screen_h)
        h = int(0.05 * self.user_screen_h)
        gap = int(0.01 * self.user_screen_h)

        self.name_layout_widget.setGeometry(0, y, self.geometry().width(), h)
        self.sign_widget.setGeometry(0, y + h, self.geometry().width(), y)

        y = int(2 * y + h + gap)
        h = int(0.09 * self.user_screen_h)
        self.table_view.setGeometry(0, y, self.geometry().width(), h)
        for i in range(5):
            self.table_view.setColumnWidth(i, self.geometry().width() / 5)
        for i in range(3):
            self.table_view.setRowHeight(i, h / 3)

        y = y + h + gap
        self.bath_list_view_widget.setGeometry(0, y, self.geometry().width(), h)

        y = y + h + gap
        self.triple_list_view_widget.setGeometry(0, y, self.geometry().width(), h)

        y = y + h + gap
        h = int(0.19 * self.user_screen_h)
        self.task_panel_widget.setGeometry(0, y, self.geometry().width(), h)
Exemplo n.º 3
0
class QtComparePanel(QWidget):

    filterChanged = pyqtSignal(str)

    def __init__(self, parent=None):
        super(QtComparePanel, self).__init__(parent)

        self.visibility_flags = []
        self.visibility_buttons = []
        self.labels_projects = []

        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)
        self.setMinimumWidth(400)
        self.setMinimumHeight(100)

        self.data_table = QTableView()
        self.data_table.setSizePolicy(QSizePolicy.MinimumExpanding,
                                      QSizePolicy.MinimumExpanding)
        self.data_table.setSelectionMode(QAbstractItemView.MultiSelection)
        self.data_table.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.data_table.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.model = None
        self.data = None

        self.combodelegate1 = ComboBoxItemDelegate(self.data_table)
        self.combodelegate2 = ComboBoxItemDelegate(self.data_table)

        lblFilter = QLabel("Filter: ")
        self.comboboxFilter = QComboBox()
        self.comboboxFilter.setMinimumWidth(80)
        self.comboboxFilter.addItem("All")
        self.comboboxFilter.addItem("Same")
        self.comboboxFilter.addItem("Born")
        self.comboboxFilter.addItem("Dead")
        self.comboboxFilter.addItem("Grow")
        self.comboboxFilter.addItem("Shrink")

        filter_layout = QHBoxLayout()
        filter_layout.addWidget(lblFilter)
        filter_layout.addWidget(self.comboboxFilter)
        filter_layout.addStretch()

        layout = QVBoxLayout()
        layout.addLayout(filter_layout)
        layout.addWidget(self.data_table)
        self.setLayout(layout)

        self.correspondences = None
        self.data = None

        self.comboboxFilter.currentTextChanged.connect(self.changeFilter)

    def setTable(self, project, img1idx, img2idx):

        self.correspondences = project.getImagePairCorrespondences(
            img1idx, img2idx)
        self.data = self.correspondences.data

        self.model = TableModel(self.data)
        self.sortfilter = QSortFilterProxyModel(self)
        self.sortfilter.setSourceModel(self.model)
        self.data_table.setModel(self.sortfilter)

        self.data_table.setVisible(False)
        self.data_table.verticalHeader().hide()
        self.data_table.resizeColumnsToContents()
        self.data_table.setVisible(True)

        self.data_table.setItemDelegateForColumn(5, self.combodelegate1)
        self.data_table.setItemDelegateForColumn(6, self.combodelegate2)
        self.data_table.setEditTriggers(QAbstractItemView.DoubleClicked)

        self.data_table.update()

        self.data_table.setStyleSheet(
            "QHeaderView::section { background-color: rgb(40,40,40) }")

    def updateData(self, corr):

        if corr is None:
            return

        self.correspondences = corr
        self.sortfilter.beginResetModel()
        self.model.beginResetModel()
        self.model._data = corr.data
        self.sortfilter.endResetModel()
        self.model.endResetModel()

        self.data_table.update()

    def selectRows(self, rows):
        self.data_table.clearSelection()

        indexes = [self.model.index(r, 0) for r in rows]
        mode = QItemSelectionModel.Select | QItemSelectionModel.Rows
        [
            self.data_table.selectionModel().select(index, mode)
            for index in indexes
        ]

        if len(rows) > 0:
            value = self.data_table.horizontalScrollBar().value()
            column = self.data_table.columnAt(value)
            self.data_table.scrollTo(self.data_table.model().index(
                rows[0], column))

    @pyqtSlot(QModelIndex)
    def getData(self, index):

        pass
        #column = index.column()
        #row = index.row()
        #self.data_table.model().index(row, column).data()

    @pyqtSlot(str)
    def changeFilter(self, txt):

        if self.data is None:
            return

        if txt == 'All':
            self.sortfilter.setFilterRegExp(QRegExp())
        else:
            self.sortfilter.setFilterKeyColumn(5)
            self.sortfilter.setFilterRegExp(txt.lower())
            self.sortfilter.setFilterRole(Qt.DisplayRole)

        self.filterChanged.emit(txt.lower())
Exemplo n.º 4
0
class WidgetDemo(QWidget):
    def __init__(self, model, rows, columns):
        super(WidgetDemo, self).__init__()
        self.init_rows = rows
        self.init_columns = columns
        self.model = model
        self.initUI(model)

    def initUI(self, model):
        self.resize(800, 800)
        self.res_pos = []
        self.focus_pos = None
        self.var_list = None
        self.signal = MySignal()
        #菜单栏
        self.menu = QMenuBar()
        self.file = self.menu.addMenu('文件')
        self.edit = self.menu.addMenu('编辑')
        self.view = self.menu.addMenu('视图')
        self.help = self.menu.addMenu('帮助')
        #各菜单下的子菜单

        #文件菜单下的子菜单
        # self.new = self.file.addAction('新建')
        self.open = self.file.addAction('打开')
        self.save = self.file.addAction('保存')
        # self.save_as = self.file.addAction('另存为')

        #编辑菜单下的子菜单
        self.cut = self.edit.addAction('剪切')
        self.copy = self.edit.addAction('复制')
        self.paste = self.edit.addAction('粘贴')
        self.delete = self.edit.addAction('删除')
        self.find = self.edit.addAction('查找')
        self.replace = self.edit.addAction('替换')

        # 快捷键
        self.open.setShortcut('Ctrl+O')
        self.save.setShortcut('Ctrl+S')
        # self.new.setShortcut('Ctrl+N')
        self.find.setShortcut('Ctrl+F')

        #视图菜单下的子菜单
        self.tool_view = QAction('工具栏', checkable=True)
        self.tool_view.setChecked(True)
        self.view.addAction(self.tool_view)

        self.statu_view = QAction('状态栏', checkable=True)
        self.statu_view.setChecked(True)
        self.view.addAction(self.statu_view)

        #帮助菜单下的子菜单
        self.about = self.help.addAction('关于')

        #工具栏
        self.tool_bar = QToolBar()
        # self.tool_bar.addAction(self.new)
        self.tool_bar.addAction(self.open)
        self.tool_bar.addAction(self.save)
        self.tool_bar.addAction(self.cut)
        self.tool_bar.addAction(self.copy)
        self.tool_bar.addAction(self.paste)
        self.tool_bar.addAction(self.find)
        # self.setting = QAction('变量设置')
        # self.setting.setEnabled(False)
        # self.tool_bar.addAction(self.setting)
        # self.tool_bar.addAction(self.replace)

        # #tool文本显示在下方
        # self.tool_bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        #findWidge
        self.find_widget = FindWidget()
        self.find_widget.hide()

        #表格
        self.table_view = QTableView()
        self.table_view.setModel(self.model)

        #状态栏
        self.status_bar = QStatusBar()
        self.status_bar.showMessage('状态栏')

        # 右键菜单栏
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.context_menu = QMenu()
        self.addRow_action = self.context_menu.addAction('增加一行')
        self.addRow_action.triggered.connect(self.addRow)
        self.delRow_action = self.context_menu.addAction('删除一行')
        self.delRow_action.triggered.connect(
            lambda: self.model.removeRow(self.table_view.currentIndex().row()))
        self.addColumn_action = self.context_menu.addAction('增加一列')
        self.addColumn_action.triggered.connect(self.addColumn)
        self.delColumn_action = self.context_menu.addAction('删除一列')
        self.delColumn_action.triggered.connect(
            lambda: self.model.removeColumn(self.table_view.currentIndex().
                                            column()))
        self.customContextMenuRequested.connect(self.rightMenuShow)

        #创建布局
        layout = QVBoxLayout()
        layout.addWidget(self.menu)
        layout.addWidget(self.tool_bar)
        layout.addWidget(self.find_widget)
        layout.addWidget(self.table_view)
        layout.addWidget(self.status_bar)
        self.setLayout(layout)

        #关联信号
        self.open.triggered.connect(self.triggeredOpen)
        self.save.triggered.connect(self.triggeredSave)
        self.tool_view.triggered.connect(self.triggeredView)
        self.statu_view.triggered.connect(self.triggeredView)
        # self.new.triggered.connect(self.triggeredNew)
        self.find.triggered.connect(self.triggeredFind)
        self.find_widget.search.triggered.connect(self.dataLocation)
        self.find_widget.down_aciton.triggered.connect(self.downAcitonLocation)
        self.find_widget.up_aciton.triggered.connect(self.upAcitonLocation)
        self.find_widget.close_aciton.triggered.connect(self.triggeredHideFind)
        self.find_widget.repalce_button.clicked.connect(self.onClickReplace)
        self.find_widget.repalceAll_button.clicked.connect(
            self.onClickReplaceAll)
        # self.setting.triggered.connect(self.triggeredSetting)

        #美化
        icon = QIcon()
        icon.addPixmap(QPixmap('./image/打开.png'), QIcon.Normal, QIcon.Off)
        self.open.setIcon(icon)
        icon.addPixmap(QPixmap('./image/保存.png'), QIcon.Normal, QIcon.Off)
        self.save.setIcon(icon)
        # icon.addPixmap(QPixmap('./image/新建.png'), QIcon.Normal, QIcon.Off)
        # self.new.setIcon(icon)
        icon.addPixmap(QPixmap('./image/剪切.png'), QIcon.Normal, QIcon.Off)
        self.cut.setIcon(icon)
        icon.addPixmap(QPixmap('./image/复制.png'), QIcon.Normal, QIcon.Off)
        self.copy.setIcon(icon)
        icon.addPixmap(QPixmap('./image/粘贴.png'), QIcon.Normal, QIcon.Off)
        self.paste.setIcon(icon)
        icon.addPixmap(QPixmap('./image/查找1.png'), QIcon.Normal, QIcon.Off)
        self.find.setIcon(icon)
        # icon.addPixmap(QPixmap('./image/设置.png'), QIcon.Normal, QIcon.Off)
        # self.setting.setIcon(icon)
        # icon.addPixmap(QPixmap('./image/替换.png'), QIcon.Normal, QIcon.Off)
        # self.replace.setIcon(icon)

    def showProgress(self, msg):
        self.status_bar.showMessage(msg)

    def loadData(self, model):
        print('load...')
        self.model = model
        self.table_view.setModel(self.model)
        qApp.processEvents()

    def triggeredOpen(self):
        self.status_bar.showMessage('打开文件', 5000)
        self.dialog = QFileDialog()
        self.dialog.setFileMode(QFileDialog.AnyFile)
        dir = r'D:/Learn-python-notes/projects/demo/Work/TCM_DSAS/data'
        self.dialog.setDirectory(dir)
        self.dialog.setFilter(QDir.Files)
        if self.dialog.exec_():
            try:
                file_name = self.dialog.selectedFiles()[0]
                #这里线程实例化一定要实例化成员变量,否则线程容易销毁
                self.thread = ReaderExcelThread(file_name)
                self.thread.standarModel_signal.connect(self.loadData)
                self.thread.progressRate_signal.connect(self.showProgress)
                self.thread.finished_signal.connect(self.thread.quit)
                self.thread.start()
                # self.setting.setEnabled(True)
            except Exception as e:
                print(e)
                pass

    def triggeredSave(self):
        self.status_bar.showMessage('保存文件', 5000)
        file_path, _ = QFileDialog.getSaveFileName(
            self, '保存文件', './data',
            'ALL Files(*);;xlsx(*.xlsx);;xls(*.xls);;csv(*.csv)')
        if file_path == '':
            return
        # 文件中写入数据
        try:
            self.write_thread = WriteExcelThread(file_path, self.model)
            self.write_thread.start_signal.connect(self.showProgress)
            self.write_thread.end_signal.connect(self.write_thread.quit)
            self.write_thread.start()
            self.status_bar.showMessage('保存完毕!')
        except Exception as e:
            print(e)

    #状态栏与工具栏的显示和隐藏
    def triggeredView(self, state):
        sender = self.sender().text()
        if sender == '工具栏':
            if state:
                self.tool_bar.show()
            else:
                self.tool_bar.hide()
        else:
            if state:
                self.status_bar.show()
            else:
                self.status_bar.hide()

    # def triggeredNew(self):
    #     print('New')
    #     pass

    def triggeredFind(self):
        self.find_widget.show()

    #重载信号,实现ESC隐藏查找窗口
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.find_widget.hide()

    #聚焦到某个cell
    def positionFocus(self, x, y):
        self.table_view.verticalScrollBar().setSliderPosition(x)
        self.table_view.horizontalScrollBar().setSliderPosition(y)
        self.table_view.openPersistentEditor(self.model.index(x, y))
        self.table_view.setFocus()

    #得到所以匹配项的位置
    def dataLocation(self):
        self.changeCellColor()
        text = self.find_widget.line_edit1.text()
        self.res_pos = []
        flag = 0
        rows = self.model.rowCount()
        columns = self.model.columnCount()
        try:
            for row in range(rows):
                for column in range(columns):
                    if text == self.model.index(row, column).data():
                        self.res_pos.append((row, column))
                        item = self.model.item(row, column)
                        item.setBackground(QColor(255, 255, 0))
                        item.setForeground(QColor(255, 0, 0))
                        #转到到第一个匹配值的位置,并处于可编辑状态
                        if not flag:
                            flag = 1
                            self.positionFocus(row, column)
                            self.focus_pos = 0
        except Exception as e:
            print(e)

    #向下跳转
    def downAcitonLocation(self):
        cnt = len(self.res_pos)
        if cnt == 0 or self.focus_pos == cnt - 1:
            return
        try:
            self.table_view.closePersistentEditor(
                self.model.index(self.res_pos[self.focus_pos][0],
                                 self.res_pos[self.focus_pos][1]))
            x, y = self.res_pos[self.focus_pos + 1]
            self.positionFocus(x, y)
            self.focus_pos += 1
        except Exception as e:
            print(e)

    # 向上跳转
    def upAcitonLocation(self):
        cnt = len(self.res_pos)
        if cnt == 0 or self.focus_pos == 0:
            return
        try:
            self.table_view.closePersistentEditor(
                self.model.index(self.res_pos[self.focus_pos][0],
                                 self.res_pos[self.focus_pos][1]))
            x, y = self.res_pos[self.focus_pos - 1]
            self.positionFocus(x, y)
            self.focus_pos -= 1
        except Exception as e:
            print(e)

    def triggeredHideFind(self):
        self.changeCellColor()
        self.find_widget.hide()

    def changeCellColor(self):
        if self.res_pos is not None and len(self.res_pos):
            self.table_view.closePersistentEditor(
                self.model.index(self.res_pos[self.focus_pos][0],
                                 self.res_pos[self.focus_pos][1]))
            for item in self.res_pos:
                x, y = item
                item = self.model.item(x, y)
                item.setBackground(QColor(255, 255, 255))
                item.setForeground(QColor(0, 0, 0))

    def onClickReplace(self):
        cnt = len(self.res_pos)
        text = self.find_widget.line_edit2.text()
        if self.res_pos is None or cnt == 0:
            return
        try:
            x, y = self.res_pos[self.focus_pos]
            self.model.setItem(x, y, QStandardItem(text))
        except Exception as e:
            print(e)

    def onClickReplaceAll(self):
        cnt = len(self.res_pos)
        if self.res_pos is None or cnt == 0:
            return
        try:
            text = self.find_widget.line_edit2.text()
            for x, y in self.res_pos:
                self.model.setItem(x, y, QStandardItem(text))
        except Exception as e:
            print(e)

    # #设置变量
    # def triggeredSetting(self):
    #     self.getVar_thread = GetVarThread(self.model)
    #     self.getVar_thread.send_signal.connect(self.initVarList)
    #     self.getVar_thread.end_signal.connect(self.getVar_thread.quit)
    #     self.getVar_thread.start()
    #
    #
    #
    # def initVarList(self,var_list):
    #     dialog = VariableSettingWindow.VariableSettingWindowDemo(var_list)
    #     dialog.signal.sender.connect(self.getVarList)
    #     dialog.show()
    #
    # def getVarList(self,lst):
    #     self.var_list = lst
    # print(lst)

    def addRow(self):
        # 当前行的下方添加一行
        try:
            self.model.insertRows(self.table_view.currentIndex().row() + 1, 1)
        except Exception as e:
            print(e)

    def addColumn(self):
        self.model.insertColumns(self.table_view.currentIndex().column() + 1,
                                 1)

    def rightMenuShow(self):
        try:
            #菜单显示的位置
            self.context_menu.popup(QCursor.pos())
            self.context_menu.show()
        except Exception as e:
            print(e)
Exemplo n.º 5
0
class WidgetDemo(QWidget):
    def __init__(self,mode):
        super(WidgetDemo,self).__init__()
        self.mode = mode
        self.initUI(mode)

    def initUI(self,mode):
        self.resize(800,800)
        #这里初始化,便于直接输入数据
        self.data = [['']*100 for i in range(15000)]
        self.res_pos = []
        self.focus_pos = None
        self.var_list = None
        #菜单栏
        self.menu = QMenuBar()
        self.file = self.menu.addMenu('文件')
        self.edit = self.menu.addMenu('编辑')
        self.view = self.menu.addMenu('视图')
        self.help = self.menu.addMenu('帮助')
        #各菜单下的子菜单

        #文件菜单下的子菜单
        self.new = self.file.addAction('新建')
        self.open = self.file.addAction('打开')
        self.save = self.file.addAction('保存')
        # self.save_as = self.file.addAction('另存为')


        #编辑菜单下的子菜单
        self.cut = self.edit.addAction('剪切')
        self.copy = self.edit.addAction('复制')
        self.paste = self.edit.addAction('粘贴')
        self.delete = self.edit.addAction('删除')
        self.find = self.edit.addAction('查找')
        self.replace = self.edit.addAction('替换')

        # 快捷键
        self.open.setShortcut('Ctrl+O')
        self.save.setShortcut('Ctrl+S')
        self.new.setShortcut('Ctrl+N')
        self.find.setShortcut('Ctrl+F')

        #视图菜单下的子菜单
        self.tool_view = QAction('工具栏',checkable=True)
        self.tool_view.setChecked(True)
        self.view.addAction(self.tool_view)

        self.statu_view = QAction('状态栏',checkable=True)
        self.statu_view.setChecked(True)
        self.view.addAction(self.statu_view)


        #帮助菜单下的子菜单
        self.about = self.help.addAction('关于')

        #工具栏
        self.tool_bar = QToolBar()
        self.tool_bar.addAction(self.new)
        self.tool_bar.addAction(self.open)
        self.tool_bar.addAction(self.save)
        self.tool_bar.addAction(self.cut)
        self.tool_bar.addAction(self.copy)
        self.tool_bar.addAction(self.paste)
        self.tool_bar.addAction(self.find)
        self.setting = QAction('变量设置')
        self.setting.setEnabled(False)
        self.tool_bar.addAction(self.setting)
        # self.tool_bar.addAction(self.replace)

        # #tool文本显示在下方
        # self.tool_bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        #findWidge
        self.find_widget = FindWidget()
        self.find_widget.hide()

        #表格
        self.table_view = QTableView()
        self.table_view.setModel(self.mode)

        #状态栏
        self.status_bar = QStatusBar()
        self.status_bar.showMessage('这是一个状态栏')


        #创建布局
        layout = QVBoxLayout()
        layout.addWidget(self.menu)
        layout.addWidget(self.tool_bar)
        layout.addWidget(self.find_widget)
        layout.addWidget(self.table_view)
        layout.addWidget(self.status_bar)
        self.setLayout(layout)

        #关联信号
        self.open.triggered.connect(self.triggeredOpen)
        self.save.triggered.connect(self.triggeredSave)
        self.mode.itemChanged.connect(self.dealItemChanged)
        self.tool_view.triggered.connect(self.triggeredView)
        self.statu_view.triggered.connect(self.triggeredView)
        self.new.triggered.connect(self.triggeredNew)
        self.find.triggered.connect(self.triggeredFind)
        self.find_widget.search.triggered.connect(self.dataLocation)
        self.find_widget.down.triggered.connect(self.downLocation)
        self.find_widget.up.triggered.connect(self.upLocation)
        self.find_widget.close.triggered.connect(self.triggeredHideFind)
        self.find_widget.repalce_button.clicked.connect(self.onClickReplace)
        self.find_widget.repalceAll_button.clicked.connect(self.onClickReplaceAll)
        self.setting.triggered.connect(self.triggeredSetting)


        #美化
        icon = QIcon()
        icon.addPixmap(QPixmap('../image/打开.png'), QIcon.Normal, QIcon.Off)
        self.open.setIcon(icon)
        icon.addPixmap(QPixmap('../image/保存.png'), QIcon.Normal, QIcon.Off)
        self.save.setIcon(icon)
        icon.addPixmap(QPixmap('../image/新建.png'), QIcon.Normal, QIcon.Off)
        self.new.setIcon(icon)
        icon.addPixmap(QPixmap('../image/剪切.png'), QIcon.Normal, QIcon.Off)
        self.cut.setIcon(icon)
        icon.addPixmap(QPixmap('../image/复制.png'), QIcon.Normal, QIcon.Off)
        self.copy.setIcon(icon)
        icon.addPixmap(QPixmap('../image/粘贴.png'), QIcon.Normal, QIcon.Off)
        self.paste.setIcon(icon)
        icon.addPixmap(QPixmap('../image/查找1.png'), QIcon.Normal, QIcon.Off)
        self.find.setIcon(icon)
        icon.addPixmap(QPixmap('../image/设置.png'), QIcon.Normal, QIcon.Off)
        self.setting.setIcon(icon)
        # icon.addPixmap(QPixmap('../image/替换.png'), QIcon.Normal, QIcon.Off)
        # self.replace.setIcon(icon)



    def triggeredOpen(self):
        self.status_bar.showMessage('打开文件',5000)
        self.dialog = QFileDialog()
        self.dialog.setFileMode(QFileDialog.AnyFile)
        dir = r'../data'
        self.dialog.setDirectory(dir)
        self.dialog.setFilter(QDir.Files)
        if self.dialog.exec_():
            try:
                start = time.time()
                file_name = self.dialog.selectedFiles()[0]
                #这里读取数据返回列表便于表格中数据的更新
                data_list = read_xlsx(file_name)
                self.data = data_list
                self.mode = QStandardItemModel()
                for rows in data_list:
                    row = [QStandardItem(str(cell)) for cell in rows]
                    self.mode.appendRow(row)
                self.mode.itemChanged.connect(self.dealItemChanged)
                self.table_view.setModel(self.mode)
                # self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
                self.table_view.resizeColumnsToContents()
                self.table_view.resizeRowsToContents()
                end = time.time()
                self.status_bar.showMessage('数据加载完毕,耗时{}秒'.format(end-start))
                self.setting.setEnabled(True)
            except Exception as e:
                print(e)
                pass

    def triggeredSave(self):
        self.status_bar.showMessage('保存文件', 5000)
        file_path, _ = QFileDialog.getSaveFileName(self, '保存文件', '../data',
                                                           'ALL Files(*);;xlsx(*.xlsx);;xls(*.xls);;csv(*.csv)')
        if file_path == '':
            return
        # 文件中写入数据
        try:
            wb = workbook.Workbook()
            wb.encoding = 'utf-8'
            wa = wb.active
            for item in self.data:
                # 过滤无效数据
                try:
                    if ''.join(item) == '':
                        continue
                except:
                    pass
                wa.append(item)
            wb.save(file_path)
            self.status_bar.showMessage('保存完毕!')
        except Exception as e:
            print(e)


    #数据变化信号处理
    def dealItemChanged(self,item):
        try:
            row,column = item.row(),item.column()
            self.data[row][column] = item.text()
        except Exception as e:
            print(e)
            pass

    #状态栏与工具栏的显示和隐藏
    def triggeredView(self,state):
        sender = self.sender().text()
        if sender == '工具栏':
            if state:
                self.tool_bar.show()
            else:
                self.tool_bar.hide()
        else:
            if state:
                self.status_bar.show()
            else:
                self.status_bar.hide()

    def triggeredNew(self):
        print('New')
        pass

    def triggeredFind(self):
        self.find_widget.show()

    #重载信号,实现ESC隐藏查找窗口
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.find_widget.hide()

    #聚焦到某个cell
    def positionFocus(self,x,y):
        self.table_view.verticalScrollBar().setSliderPosition(x)
        self.table_view.horizontalScrollBar().setSliderPosition(y)
        self.table_view.openPersistentEditor(self.mode.index(x, y))
        self.table_view.setFocus()

    #得到所以匹配项的位置
    def dataLocation(self):
        text = self.find_widget.line_edit1.text()
        self.res_pos = []
        flag = 0
        for i,row in enumerate(self.data):
            try:
                if ''.join(row) == '':
                    continue
            except:
                pass
            for j,cell in enumerate(row):
                if text == str(cell):
                    # print(i,j)
                    self.res_pos.append((i,j))
                    item = self.mode.item(i,j)
                    item.setBackground(QColor(255, 255, 0))
                    item.setForeground(QColor(255, 0, 0))
                    #转到到第一个匹配值的位置,并处于可编辑状态
                    if not flag:
                        flag = 1
                        self.positionFocus(i,j)
                        self.focus_pos = 0

    #向下跳转
    def downLocation(self):
        cnt = len(self.res_pos)
        if cnt == 0 or self.focus_pos == cnt-1:
            return
        try:
            self.table_view.closePersistentEditor(
                self.mode.index(self.res_pos[self.focus_pos][0],self.res_pos[self.focus_pos][1]))
            x, y = self.res_pos[self.focus_pos + 1]
            self.positionFocus(x,y)
            self.focus_pos += 1
        except Exception as e:
            print(e)

    # 向上跳转
    def upLocation(self):
        cnt = len(self.res_pos)
        if cnt == 0 or self.focus_pos == 0:
            return
        try:
            self.table_view.closePersistentEditor(
                self.mode.index(self.res_pos[self.focus_pos][0], self.res_pos[self.focus_pos][1]))
            x, y = self.res_pos[self.focus_pos - 1]
            self.positionFocus(x, y)
            self.focus_pos -= 1
        except Exception as e:
            print(e)


    def triggeredHideFind(self):
        if self.res_pos is not None and len(self.res_pos):
            self.table_view.closePersistentEditor(
                self.mode.index(self.res_pos[self.focus_pos][0], self.res_pos[self.focus_pos][1]))
            for item in self.res_pos:
                x,y = item
                item = self.mode.item(x,y)
                item.setBackground(QColor(255, 255, 255))
                item.setForeground(QColor(0, 0, 0))
        self.find_widget.hide()


    #不清楚如何修改cell值,替换功能暂时无法上线
    def onClickReplace(self):
        print('-'*50)
        cnt = len(self.res_pos)
        if self.res_pos is None or cnt == 0:
            return
        try:

            x, y = self.res_pos[self.focus_pos]
            text = self.find_widget.line_edit2.text()
            self.data[x][y] = text
            print(self.data[x][y])
        except Exception as e:
            print(e)

    def onClickReplaceAll(self):
        pass
    #设置变量
    def triggeredSetting(self):
        # 设置变量窗口
        var_list = self.data[0] if self.data[0][0]!='' else self.data[0][1:]
        self.dialog = VariableSettingWindow.VariableSettingWindowDemo(var_list)
        self.dialog.signal.sender.connect(self.getVarList)
        self.dialog.show()

    def getVarList(self,lst):
        self.var_list = lst