class MLineTabWidget(QWidget): """MLineTabWidget""" def __init__(self, alignment=Qt.AlignCenter, parent=None): super(MLineTabWidget, self).__init__(parent=parent) self.tool_button_group = MUnderlineButtonGroup() self.bar_layout = QHBoxLayout() self.bar_layout.setContentsMargins(0, 0, 0, 0) if alignment == Qt.AlignCenter: self.bar_layout.addStretch() self.bar_layout.addWidget(self.tool_button_group) self.bar_layout.addStretch() elif alignment == Qt.AlignLeft: self.bar_layout.addWidget(self.tool_button_group) self.bar_layout.addStretch() elif alignment == Qt.AlignRight: self.bar_layout.addStretch() self.bar_layout.addWidget(self.tool_button_group) self.stack_widget = MStackedWidget() self.tool_button_group.sig_checked_changed.connect( self.stack_widget.setCurrentIndex) main_lay = QVBoxLayout() main_lay.setContentsMargins(0, 0, 0, 0) main_lay.setSpacing(0) main_lay.addLayout(self.bar_layout) main_lay.addWidget(MDivider()) main_lay.addSpacing(5) main_lay.addWidget(self.stack_widget) self.setLayout(main_lay) def add_tab(self, widget, data_dict): """Add a tab""" self.stack_widget.addWidget(widget) self.tool_button_group.add_button(data_dict, self.stack_widget.count() - 1)
class MMenuTabWidget(QWidget): """MMenuTabWidget""" def __init__(self, parent=None): super(MMenuTabWidget, self).__init__(parent=parent) self.tool_button_group = MBlockButtonGroup() self._bar_layout = QHBoxLayout() self._bar_layout.setContentsMargins(10, 0, 10, 0) self._bar_layout.addWidget(self.tool_button_group) self._bar_layout.addStretch() bar_widget = QWidget() bar_widget.setObjectName('bar_widget') bar_widget.setLayout(self._bar_layout) bar_widget.setAttribute(Qt.WA_StyledBackground) main_lay = QVBoxLayout() main_lay.setContentsMargins(0, 0, 0, 0) main_lay.setSpacing(0) main_lay.addWidget(bar_widget) main_lay.addWidget(MDivider()) main_lay.addSpacing(5) self.setLayout(main_lay) self.setFixedHeight(dayu_theme.large + 10) def tool_bar_append_widget(self, widget): """Add the widget too menubar's right position.""" self._bar_layout.addWidget(widget) def tool_bar_insert_widget(self, widget): """Insert the widget to menubar's left position.""" self._bar_layout.insertWidget(0, widget) def add_menu(self, data_dict, index=None): """Add a menu""" self.tool_button_group.add_button(data_dict, index)
def _init_ui(self): # 工具 item_list = [ {'text': u'文件', 'svg': 'folder_line.svg', 'clicked': self.openFile}, {'text': u'编辑', 'svg': 'edit_line.svg', 'clicked': self.editFile}, {'text': u'关于', 'svg': 'warning_line.svg', 'clicked': self.showAbout}, ] tool_bar = MMenuTabWidget() tool_bar.tool_bar_insert_widget(MLabel('Zeus').h4().secondary().strong()) self.user_toolButton = MToolButton().large() pixmap = QPixmap(file_path + "\\res\\headPortrial\\user_default.png") self.user_toolButton.setIcon(pixmap) tool_bar.tool_bar_append_widget( MBadge.dot(show=False, widget=self.user_toolButton)) self.label = MLabel(u"未登录") tool_bar.tool_bar_append_widget( MBadge.dot(show=False, widget=self.label)) for index, data_dict in enumerate(item_list): tool_bar.add_menu(data_dict, index) main_lay = QHBoxLayout() main_lay.setContentsMargins(0, 0, 0, 0) main_lay.addWidget(tool_bar) self.setLayout(main_lay) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self.user_toolButton.clicked.connect(self.setUser)
def __init__(self, view_type=None, parent=None): super(MItemViewSet, self).__init__(parent) self._main_lay = QVBoxLayout() self._main_lay.setSpacing(5) self._main_lay.setContentsMargins(0, 0, 0, 0) self.sort_filter_model = MSortFilterModel() self.source_model = MTableModel() self.sort_filter_model.setSourceModel(self.source_model) view_class = view_type or MItemViewSet.TableViewType self.item_view = view_class() self.item_view.doubleClicked.connect(self.sig_double_clicked) self.item_view.pressed.connect(self.slot_left_clicked) self.item_view.setModel(self.sort_filter_model) self._search_line_edit = MLineEdit().search().small() self._search_attr_button = MToolButton().icon_only().svg( 'down_fill.svg').small() self._search_line_edit.set_prefix_widget(self._search_attr_button) self._search_line_edit.textChanged.connect( self.sort_filter_model.set_search_pattern) self._search_line_edit.setVisible(False) _search_lay = QHBoxLayout() _search_lay.setContentsMargins(0, 0, 0, 0) _search_lay.addStretch() _search_lay.addWidget(self._search_line_edit) self._main_lay.addLayout(_search_lay) self._main_lay.addWidget(self.item_view) self.setLayout(self._main_lay)
class MCard(QWidget): def __init__(self, title=None, image=None, size=None, extra=None, type=None, parent=None): super(MCard, self).__init__(parent=parent) self.setAttribute(Qt.WA_StyledBackground) self.setProperty('border', False) size = size or dayu_theme.default_size map_label = { dayu_theme.large: (MLabel.H2Level, 20), dayu_theme.medium: (MLabel.H3Level, 15), dayu_theme.small: (MLabel.H4Level, 10), } self._title_label = MLabel(text=title) self._title_label.set_dayu_level(map_label.get(size)[0]) padding = map_label.get(size)[-1] self._title_layout = QHBoxLayout() self._title_layout.setContentsMargins(padding, padding, padding, padding) if image: self._title_icon = MAvatar() self._title_icon.set_dayu_image(image) self._title_icon.set_dayu_size(size) self._title_layout.addWidget(self._title_icon) self._title_layout.addWidget(self._title_label) self._title_layout.addStretch() if extra: self._extra_button = MToolButton().icon_only().svg('more.svg') self._title_layout.addWidget(self._extra_button) self._content_layout = QVBoxLayout() self._main_lay = QVBoxLayout() self._main_lay.setSpacing(0) self._main_lay.setContentsMargins(1, 1, 1, 1) if title: self._main_lay.addLayout(self._title_layout) self._main_lay.addWidget(MDivider()) self._main_lay.addLayout(self._content_layout) self.setLayout(self._main_lay) def get_more_button(self): return self._extra_button def set_widget(self, widget): self._content_layout.addWidget(widget) def border(self): self.setProperty('border', True) self.style().polish(self) return self
class MLineEdit(QLineEdit): """MLineEdit""" sig_delay_text_changed = Signal(basestring) def __init__(self, text='', parent=None): super(MLineEdit, self).__init__(text, parent) self._main_layout = QHBoxLayout() self._main_layout.setContentsMargins(0, 0, 0, 0) self._main_layout.addStretch() self._prefix_widget = None self._suffix_widget = None self.setLayout(self._main_layout) self.setProperty('history', self.property('text')) self.setTextMargins(2, 0, 2, 0) self._delay_timer = QTimer() self._delay_timer.setInterval(500) self._delay_timer.setSingleShot(True) self._delay_timer.timeout.connect(self._slot_delay_text_changed) self._dayu_size = dayu_theme.default_size def get_dayu_size(self): """ Get the push button height :return: integer """ return self._dayu_size def set_dayu_size(self, value): """ Set the avatar size. :param value: integer :return: None """ self._dayu_size = value if hasattr(self._prefix_widget, 'set_dayu_size'): self._prefix_widget.set_dayu_size(self._dayu_size) if hasattr(self._suffix_widget, 'set_dayu_size'): self._suffix_widget.set_dayu_size(self._dayu_size) self.style().polish(self) dayu_size = Property(int, get_dayu_size, set_dayu_size) def set_delay_duration(self, millisecond): """Set delay timer's timeout duration.""" self._delay_timer.setInterval(millisecond) @Slot() def _slot_delay_text_changed(self): self.sig_delay_text_changed.emit(self.text()) def get_prefix_widget(self): """Get the prefix widget for user to edit""" return self._prefix_widget def set_prefix_widget(self, widget): """Set the line edit left start widget""" if self._prefix_widget: index = self._main_layout.indexOf(self._prefix_widget) self._main_layout.takeAt(index) self._prefix_widget.setVisible(False) # if isinstance(widget, MPushButton): widget.setProperty('combine', 'horizontal') widget.setProperty('position', 'left') if hasattr(widget, 'set_dayu_size'): widget.set_dayu_size(self._dayu_size) margin = self.textMargins() margin.setLeft(margin.left() + widget.width()) self.setTextMargins(margin) self._main_layout.insertWidget(0, widget) self._prefix_widget = widget return widget def get_suffix_widget(self): """Get the suffix widget for user to edit""" return self._suffix_widget def set_suffix_widget(self, widget): """Set the line edit right end widget""" if self._suffix_widget: index = self._main_layout.indexOf(self._suffix_widget) self._main_layout.takeAt(index) self._suffix_widget.setVisible(False) # if isinstance(widget, MPushButton): widget.setProperty('combine', 'horizontal') widget.setProperty('position', 'right') if hasattr(widget, 'set_dayu_size'): widget.set_dayu_size(self._dayu_size) margin = self.textMargins() margin.setRight(margin.right() + widget.width()) self.setTextMargins(margin) self._main_layout.addWidget(widget) self._suffix_widget = widget return widget def setText(self, text): """Override setText save text to history""" self.setProperty('history', u'{}\n{}'.format(self.property('history'), text)) return super(MLineEdit, self).setText(text) def clear(self): """Override clear to clear history""" self.setProperty('history', '') return super(MLineEdit, self).clear() def keyPressEvent(self, event): """Override keyPressEvent to start delay timer""" if event.key() not in [Qt.Key_Enter, Qt.Key_Tab]: if self._delay_timer.isActive(): self._delay_timer.stop() self._delay_timer.start() super(MLineEdit, self).keyPressEvent(event) def search(self): """Add a search icon button for MLineEdit.""" suffix_button = MToolButton().icon_only().svg('close_line.svg') suffix_button.clicked.connect(self.clear) self.set_suffix_widget(suffix_button) self.setPlaceholderText(self.tr('Enter key word to search...')) return self def error(self): """A a toolset to MLineEdit to store error info with red style""" @Slot() def _slot_show_detail(self): dialog = QTextEdit(self) dialog.setReadOnly(True) geo = QApplication.desktop().screenGeometry() dialog.setGeometry(geo.width() / 2, geo.height() / 2, geo.width() / 4, geo.height() / 4) dialog.setWindowTitle(self.tr('Error Detail Information')) dialog.setText(self.property('history')) dialog.setWindowFlags(Qt.Dialog) dialog.show() self.setProperty('dayu_type', 'error') self.setReadOnly(True) _suffix_button = MToolButton().icon_only().svg('detail_line.svg') _suffix_button.clicked.connect( functools.partial(_slot_show_detail, self)) self.set_suffix_widget(_suffix_button) self.setPlaceholderText(self.tr('Error information will be here...')) return self def search_engine(self, text='Search'): """Add a MPushButton to suffix for MLineEdit""" _suffix_button = MPushButton(text=text).primary() _suffix_button.clicked.connect(self.returnPressed) _suffix_button.setFixedWidth(100) self.set_suffix_widget(_suffix_button) self.setPlaceholderText(self.tr('Enter key word to search...')) return self def file(self, filters=None): """Add a MClickBrowserFileToolButton for MLineEdit to select file""" _suffix_button = MClickBrowserFileToolButton() _suffix_button.sig_file_changed.connect(self.setText) _suffix_button.set_dayu_filters(filters or []) self.textChanged.connect(_suffix_button.set_dayu_path) self.set_suffix_widget(_suffix_button) self.setPlaceholderText(self.tr('Click button to browser files')) return self def folder(self): """Add a MClickBrowserFolderToolButton for MLineEdit to select folder""" _suffix_button = MClickBrowserFolderToolButton() _suffix_button.sig_folder_changed.connect(self.setText) self.textChanged.connect(_suffix_button.set_dayu_path) self.set_suffix_widget(_suffix_button) self.setPlaceholderText(self.tr('Click button to browser folder')) return self def huge(self): """Set MLineEdit to huge size""" self.set_dayu_size(dayu_theme.huge) return self def large(self): """Set MLineEdit to large size""" self.set_dayu_size(dayu_theme.large) return self def medium(self): """Set MLineEdit to medium""" self.set_dayu_size(dayu_theme.medium) return self def small(self): """Set MLineEdit to small size""" self.set_dayu_size(dayu_theme.small) return self def tiny(self): """Set MLineEdit to tiny size""" self.set_dayu_size(dayu_theme.tiny) return self def password(self): """Set MLineEdit to password echo mode""" self.setEchoMode(QLineEdit.Password) return self
def __init__(self, parent=None): super(MPage, self).__init__(parent) self.register_field('page_size_selected', 25) self.register_field('page_size_list', [{'label': '25 - Fastest', 'value': 25}, {'label': '50 - Fast', 'value': 50}, {'label': '75 - Medium', 'value': 75}, {'label': '100 - Slow', 'value': 100}]) self.register_field('total', 0) self.register_field('current_page', 0) self.register_field('total_page', lambda: utils.get_total_page(self.field('total'), self.field('page_size_selected'))) self.register_field('total_page_text', lambda: str(self.field('total_page'))) self.register_field('display_text', lambda: utils.get_page_display_string(self.field('current_page'), self.field('page_size_selected'), self.field('total'))) self.register_field('can_pre', lambda: self.field('current_page') > 1) self.register_field('can_next', lambda: self.field('current_page') < self.field('total_page')) page_setting_menu = MMenu(parent=self) self._display_label = MLabel() self._display_label.setAlignment(Qt.AlignCenter) self._change_page_size_button = MComboBox().small() self._change_page_size_button.setFixedWidth(110) self._change_page_size_button.set_menu(page_setting_menu) self._change_page_size_button.set_formatter(lambda x: u'{} per page'.format(x)) self._change_page_size_button.sig_value_changed.connect(self._emit_page_changed) self._pre_button = MToolButton().icon_only().svg('left_fill.svg').small() self._pre_button.clicked.connect(functools.partial(self._slot_change_current_page, -1)) self._next_button = MToolButton().small().icon_only().svg('right_fill.svg') self._next_button.clicked.connect(functools.partial(self._slot_change_current_page, 1)) self._current_page_spin_box = MSpinBox() self._current_page_spin_box.setMinimum(1) self._current_page_spin_box.set_dayu_size(dayu_theme.small) self._current_page_spin_box.valueChanged.connect(self._emit_page_changed) self._total_page_label = MLabel() self.bind('page_size_list', page_setting_menu, 'data') self.bind('page_size_selected', page_setting_menu, 'value', signal='sig_value_changed') self.bind('page_size_selected', self._change_page_size_button, 'value', signal='sig_value_changed') self.bind('current_page', self._current_page_spin_box, 'value', signal='valueChanged') self.bind('total_page', self._current_page_spin_box, 'maximum') self.bind('total_page_text', self._total_page_label, 'dayu_text') self.bind('display_text', self._display_label, 'dayu_text') self.bind('can_pre', self._pre_button, 'enabled') self.bind('can_next', self._next_button, 'enabled') main_lay = QHBoxLayout() main_lay.setContentsMargins(0, 0, 0, 0) main_lay.setSpacing(2) main_lay.addStretch() main_lay.addWidget(self._display_label) main_lay.addStretch() main_lay.addWidget(MLabel('|').secondary()) main_lay.addWidget(self._change_page_size_button) main_lay.addWidget(MLabel('|').secondary()) main_lay.addWidget(self._pre_button) main_lay.addWidget(MLabel('Page')) main_lay.addWidget(self._current_page_spin_box) main_lay.addWidget(MLabel('/')) main_lay.addWidget(self._total_page_label) main_lay.addWidget(self._next_button) self.setLayout(main_lay)
class MAlert(QWidget): """ Alert component for feedback. Property: dayu_type: The feedback type with different color container. dayu_text: The feedback string showed in container. """ InfoType = 'info' SuccessType = 'success' WarningType = 'warning' ErrorType = 'error' def __init__(self, text='', parent=None, flags=0): super(MAlert, self).__init__(parent, flags) self.setAttribute(Qt.WA_StyledBackground) self._icon_label = MAvatar() self._icon_label.set_dayu_size(dayu_theme.tiny) self._content_label = MLabel().secondary() self._close_button = MToolButton().svg( 'close_line.svg').tiny().icon_only() self._close_button.clicked.connect( functools.partial(self.setVisible, False)) self._main_lay = QHBoxLayout() self._main_lay.setContentsMargins(8, 8, 8, 8) self._main_lay.addWidget(self._icon_label) self._main_lay.addWidget(self._content_label) self._main_lay.addStretch() self._main_lay.addWidget(self._close_button) self.setLayout(self._main_lay) self.set_show_icon(True) self.set_closeable(False) self._dayu_type = None self._dayu_text = None self.set_dayu_type(MAlert.InfoType) self.set_dayu_text(text) def set_closeable(self, closeable): """Display the close icon button or not.""" self._close_button.setVisible(closeable) def set_show_icon(self, show_icon): """Display the information type icon or not.""" self._icon_label.setVisible(show_icon) def _set_dayu_text(self): self._content_label.setText(self._dayu_text) self.setVisible(bool(self._dayu_text)) def set_dayu_text(self, value): """Set the feedback content.""" if isinstance(value, basestring): self._dayu_text = value else: raise TypeError("Input argument 'value' should be string type, " "but get {}".format(type(value))) self._set_dayu_text() def _set_dayu_type(self): self._icon_label.set_dayu_image( MPixmap('{}_fill.svg'.format(self._dayu_type), vars(dayu_theme).get(self._dayu_type + '_color'))) self.style().polish(self) def set_dayu_type(self, value): """Set feedback type.""" if value in [ MAlert.InfoType, MAlert.SuccessType, MAlert.WarningType, MAlert.ErrorType ]: self._dayu_type = value else: raise ValueError("Input argument 'value' should be one of " "info/success/warning/error string.") self._set_dayu_type() def get_dayu_type(self): """ Get MAlert feedback type. :return: str """ return self._dayu_type def get_dayu_text(self): """ Get MAlert feedback message. :return: basestring """ return self._dayu_text dayu_text = Property(unicode, get_dayu_text, set_dayu_text) dayu_type = Property(str, get_dayu_type, set_dayu_type) def info(self): """Set MAlert to InfoType""" self.set_dayu_type(MAlert.InfoType) return self def success(self): """Set MAlert to SuccessType""" self.set_dayu_type(MAlert.SuccessType) return self def warning(self): """Set MAlert to WarningType""" self.set_dayu_type(MAlert.WarningType) return self def error(self): """Set MAlert to ErrorType""" self.set_dayu_type(MAlert.ErrorType) return self def closable(self): """Set MAlert closebale is True""" self.set_closeable(True) return self
class MTag(QLabel): """ Tag for categorizing or markup. """ sig_closed = Signal() sig_clicked = Signal() def __init__(self, text='', parent=None): super(MTag, self).__init__(text=text, parent=parent) self._is_pressed = False self._close_button = MToolButton().tiny().svg('close_line.svg').icon_only() self._close_button.clicked.connect(self.sig_closed) self._close_button.clicked.connect(self.close) self._close_button.setVisible(False) self._main_lay = QHBoxLayout() self._main_lay.setContentsMargins(0, 0, 0, 0) self._main_lay.addStretch() self._main_lay.addWidget(self._close_button) self.setLayout(self._main_lay) self._clickable = False self._border = True self._border_style = QssTemplate(''' MTag{ font-size: 12px; padding: 3px; color: @text_color; border-radius: @border_radius; border: 1px solid @border_color; background-color: @background_color; } MTag:hover{ color: @hover_color; } ''') self._no_border_style = QssTemplate(''' MTag{ font-size: 12px; padding: 4px; border-radius: @border_radius; color: @text_color; border: 0 solid @border_color; background-color: @background_color; } MTag:hover{ background-color:@hover_color; } ''') self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self._color = None self.set_dayu_color(dayu_theme.secondary_text_color) def minimumSizeHint(self, *args, **kwargs): """Override minimumSizeHint for expand width when the close button is visible.""" orig = super(MTag, self).minimumSizeHint(*args, **kwargs) orig.setWidth(orig.width() + (dayu_theme.tiny if self._close_button.isVisible() else 0)) return orig def get_dayu_color(self): """Get tag's color""" return self._color def set_dayu_color(self, value): """Set Tag primary color.""" self._color = value self._update_style() def _update_style(self): if self._border: self.setStyleSheet( self._border_style.substitute(background_color=utils.fade_color(self._color, '15%'), border_radius=dayu_theme.border_radius_base, border_color=utils.fade_color(self._color, '35%'), hover_color=utils.generate_color(self._color, 5), text_color=self._color)) else: self.setStyleSheet(self._no_border_style.substitute( background_color=utils.generate_color(self._color, 6), border_radius=dayu_theme.border_radius_base, border_color=utils.generate_color(self._color, 6), hover_color=utils.generate_color(self._color, 5), text_color=dayu_theme.text_color_inverse)) dayu_color = Property(str, get_dayu_color, set_dayu_color) def mousePressEvent(self, event): """Override mousePressEvent to flag _is_pressed.""" if event.button() == Qt.LeftButton: self._is_pressed = True return super(MTag, self).mousePressEvent(event) def leaveEvent(self, event): """Override leaveEvent to reset _is_pressed flag.""" self._is_pressed = False return super(MTag, self).leaveEvent(event) def mouseReleaseEvent(self, event): """Override mouseReleaseEvent to emit sig_clicked signal.""" if event.button() == Qt.LeftButton and self._is_pressed: if self._clickable: self.sig_clicked.emit() self._is_pressed = False return super(MTag, self).mouseReleaseEvent(event) def closeable(self): """Set Tag can be closed and show the close icon button.""" self._close_button.setVisible(True) return self def clickable(self): """Set Tag can be clicked and change the cursor to pointing-hand shape when enter.""" self.setCursor(Qt.PointingHandCursor) self._clickable = True return self def no_border(self): """Set Tag style is border or fill.""" self._border = False self._update_style() return self def coloring(self, color): """Same as set_dayu_color. Support chain.""" self.set_dayu_color(color) return self
class MBreadcrumb(QWidget): """ MBreadcrumb A breadcrumb displays the current location within a hierarchy. It allows going back to states higher up in the hierarchy. """ def __init__(self, separator='/', parent=None): super(MBreadcrumb, self).__init__(parent) self._separator = separator self._main_layout = QHBoxLayout() self._main_layout.setContentsMargins(0, 0, 0, 0) self._main_layout.setSpacing(0) self._main_layout.addStretch() self.setLayout(self._main_layout) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self._button_group = QButtonGroup() self._label_list = [] def set_item_list(self, data_list): """Set the whole breadcrumb items. It will clear the old widgets.""" for button in self._button_group.buttons(): self._button_group.removeButton(button) self._main_layout.removeWidget(button) button.setVisible(False) for sep in self._label_list: self._button_group.removeButton(sep) self._main_layout.removeWidget(sep) sep.setVisible(False) for index, data_dict in enumerate(data_list): self.add_item(data_dict, index) def add_item(self, data_dict, index=None): """Add a item""" button = MToolButton() button.setText(data_dict.get('text')) if data_dict.get('svg'): button.svg(data_dict.get('svg')) if data_dict.get('tooltip'): button.setProperty('toolTip', data_dict.get('tooltip')) if data_dict.get('clicked'): button.clicked.connect(data_dict.get('clicked')) if data_dict.get('text'): if data_dict.get('svg') or data_dict.get('icon'): button.text_beside_icon() else: button.text_only() else: button.icon_only() if self._button_group.buttons(): separator = MLabel(self._separator).secondary() self._label_list.append(separator) self._main_layout.insertWidget(self._main_layout.count() - 1, separator) self._main_layout.insertWidget(self._main_layout.count() - 1, button) if index is None: self._button_group.addButton(button) else: self._button_group.addButton(button, index)
class MItemViewFullSet(QWidget): sig_double_clicked = Signal(QModelIndex) sig_left_clicked = Signal(QModelIndex) sig_current_changed = Signal(QModelIndex, QModelIndex) sig_current_row_changed = Signal(QModelIndex, QModelIndex) sig_current_column_changed = Signal(QModelIndex, QModelIndex) sig_selection_changed = Signal(QItemSelection, QItemSelection) sig_context_menu = Signal(object) def __init__(self, table_view=True, big_view=False, parent=None): super(MItemViewFullSet, self).__init__(parent) self.sort_filter_model = MSortFilterModel() self.source_model = MTableModel() self.sort_filter_model.setSourceModel(self.source_model) self.stack_widget = QStackedWidget() self.view_button_grp = MToolButtonGroup(exclusive=True) data_group = [] if table_view: self.table_view = MTableView(show_row_count=True) self.table_view.doubleClicked.connect(self.sig_double_clicked) self.table_view.pressed.connect(self.slot_left_clicked) self.table_view.setModel(self.sort_filter_model) self.stack_widget.addWidget(self.table_view) data_group.append({ 'svg': 'table_view.svg', 'checkable': True, 'tooltip': u'Table View' }) if big_view: self.big_view = MBigView() self.big_view.doubleClicked.connect(self.sig_double_clicked) self.big_view.pressed.connect(self.slot_left_clicked) self.big_view.setModel(self.sort_filter_model) self.stack_widget.addWidget(self.big_view) data_group.append({ 'svg': 'big_view.svg', 'checkable': True, 'tooltip': u'Big View' }) # 设置多个view 共享 MItemSelectionModel leader_view = self.stack_widget.widget(0) self.selection_model = leader_view.selectionModel() for index in range(self.stack_widget.count()): if index == 0: continue other_view = self.stack_widget.widget(index) other_view.setSelectionModel(self.selection_model) self.selection_model.currentChanged.connect(self.sig_current_changed) self.selection_model.currentRowChanged.connect( self.sig_current_row_changed) self.selection_model.currentColumnChanged.connect( self.sig_current_column_changed) self.selection_model.selectionChanged.connect( self.sig_selection_changed) self.tool_bar = QWidget() self.top_lay = QHBoxLayout() self.top_lay.setContentsMargins(0, 0, 0, 0) if data_group and len(data_group) > 1: self.view_button_grp.sig_checked_changed.connect( self.stack_widget.setCurrentIndex) self.view_button_grp.set_button_list(data_group) self.view_button_grp.set_dayu_checked(0) self.top_lay.addWidget(self.view_button_grp) self.search_line_edit = MLineEdit().search().small() self.search_attr_button = MToolButton().icon_only().svg( 'down_fill.svg').small() self.search_line_edit.set_prefix_widget(self.search_attr_button) self.search_line_edit.textChanged.connect( self.sort_filter_model.set_search_pattern) self.search_line_edit.setVisible(False) self.top_lay.addStretch() self.top_lay.addWidget(self.search_line_edit) self.tool_bar.setLayout(self.top_lay) self.page_set = MPage() self.main_lay = QVBoxLayout() self.main_lay.setSpacing(5) self.main_lay.setContentsMargins(0, 0, 0, 0) self.main_lay.addWidget(self.tool_bar) self.main_lay.addWidget(self.stack_widget) self.main_lay.addWidget(self.page_set) self.setLayout(self.main_lay) def enable_context_menu(self): for index in range(self.stack_widget.count()): view = self.stack_widget.widget(index) view.enable_context_menu(True) view.sig_context_menu.connect(self.sig_context_menu) def set_no_data_text(self, text): for index in range(self.stack_widget.count()): view = self.stack_widget.widget(index) view.set_no_data_text(text) def set_selection_mode(self, mode): for index in range(self.stack_widget.count()): view = self.stack_widget.widget(index) view.setSelectionMode(mode) def tool_bar_visible(self, flag): self.tool_bar.setVisible(flag) @Slot(QModelIndex) def slot_left_clicked(self, start_index): button = QApplication.mouseButtons() if button == Qt.LeftButton: real_index = self.sort_filter_model.mapToSource(start_index) self.sig_left_clicked.emit(real_index) def set_header_list(self, header_list): self.source_model.set_header_list(header_list) self.sort_filter_model.set_header_list(header_list) self.sort_filter_model.setSourceModel(self.source_model) for index in range(self.stack_widget.count()): view = self.stack_widget.widget(index) view.set_header_list(header_list) def tool_bar_append_widget(self, widget): self.top_lay.addWidget(widget) def tool_bar_insert_widget(self, widget): self.top_lay.insertWidget(0, widget) @Slot() def setup_data(self, data_list): self.source_model.clear() if data_list: self.source_model.set_data_list(data_list) self.set_record_count(len(data_list)) @Slot(int) def set_record_count(self, total): self.page_set.set_total(total) def get_data(self): return self.source_model.get_data_list() def searchable(self): """Enable search line edit visible.""" self.search_line_edit.setVisible(True) return self
class MItemViewSet(QWidget): sig_double_clicked = Signal(QModelIndex) sig_left_clicked = Signal(QModelIndex) TableViewType = MTableView BigViewType = MBigView TreeViewType = MTreeView ListViewType = MListView def __init__(self, view_type=None, parent=None): super(MItemViewSet, self).__init__(parent) self.main_lay = QVBoxLayout() self.main_lay.setSpacing(5) self.main_lay.setContentsMargins(0, 0, 0, 0) self.sort_filter_model = MSortFilterModel() self.source_model = MTableModel() self.sort_filter_model.setSourceModel(self.source_model) view_class = view_type or MItemViewSet.TableViewType self.item_view = view_class() self.item_view.doubleClicked.connect(self.sig_double_clicked) self.item_view.pressed.connect(self.slot_left_clicked) self.item_view.setModel(self.sort_filter_model) self._search_line_edit = MLineEdit().search().small() self._search_attr_button = MToolButton().icon_only().svg( 'down_fill.svg').small() self._search_line_edit.set_prefix_widget(self._search_attr_button) self._search_line_edit.textChanged.connect( self.sort_filter_model.set_search_pattern) self._search_line_edit.setVisible(False) self._search_lay = QHBoxLayout() self._search_lay.setContentsMargins(0, 0, 0, 0) self._search_lay.addStretch() self._search_lay.addWidget(self._search_line_edit) self.main_lay.addLayout(self._search_lay) self.main_lay.addWidget(self.item_view) self.setLayout(self.main_lay) @Slot(QModelIndex) def slot_left_clicked(self, start_index): button = QApplication.mouseButtons() if button == Qt.LeftButton: real_index = self.sort_filter_model.mapToSource(start_index) self.sig_left_clicked.emit(real_index) def set_header_list(self, header_list): self.source_model.set_header_list(header_list) self.sort_filter_model.set_header_list(header_list) self.sort_filter_model.setSourceModel(self.source_model) self.item_view.set_header_list(header_list) @Slot() def setup_data(self, data_list): self.source_model.clear() if data_list: self.source_model.set_data_list(data_list) def get_data(self): return self.source_model.get_data_list() def searchable(self): """Enable search line edit visible.""" self._search_line_edit.setVisible(True) return self def insert_widget(self, widget): """Use can insert extra widget into search layout.""" self._search_lay.insertWidget(0, widget)
class MDivider(QWidget): ''' A divider line separates different content. Property: dayu_text: six.string_types ''' _alignment_map = { Qt.AlignCenter: 50, Qt.AlignLeft: 20, Qt.AlignRight: 80, } def __init__(self, text='', orientation=Qt.Horizontal, alignment=Qt.AlignCenter, parent=None): super(MDivider, self).__init__(parent) self._orient = orientation self._text_label = MLabel().secondary() self._left_frame = QFrame() self._right_frame = QFrame() self._main_lay = QHBoxLayout() self._main_lay.setContentsMargins(0, 0, 0, 0) self._main_lay.setSpacing(0) self._main_lay.addWidget(self._left_frame) self._main_lay.addWidget(self._text_label) self._main_lay.addWidget(self._right_frame) self.setLayout(self._main_lay) if orientation == Qt.Horizontal: self._left_frame.setFrameShape(QFrame.HLine) self._left_frame.setFrameShadow(QFrame.Sunken) self._right_frame.setFrameShape(QFrame.HLine) self._right_frame.setFrameShadow(QFrame.Sunken) else: self._text_label.setVisible(False) self._right_frame.setVisible(False) self._left_frame.setFrameShape(QFrame.VLine) self._left_frame.setFrameShadow(QFrame.Plain) self.setFixedWidth(2) self._main_lay.setStretchFactor(self._left_frame, self._alignment_map.get(alignment, 50)) self._main_lay.setStretchFactor(self._right_frame, 100 - self._alignment_map.get(alignment, 50)) self._text = None self.set_dayu_text(text) def set_dayu_text(self, value): """ Set the divider's text. When text is empty, hide the text_label and right_frame to ensure the divider not has a gap. :param value: six.string_types :return: None """ self._text = value self._text_label.setText(value) if self._orient == Qt.Horizontal: self._text_label.setVisible(bool(value)) self._right_frame.setVisible(bool(value)) def get_dayu_text(self): """ Get current text :return: six.string_types """ return self._text dayu_text = Property(six.string_types[0], get_dayu_text, set_dayu_text) @classmethod def left(cls, text=''): """Create a horizontal divider with text at left.""" return cls(text, alignment=Qt.AlignLeft) @classmethod def right(cls, text=''): """Create a horizontal divider with text at right.""" return cls(text, alignment=Qt.AlignRight) @classmethod def center(cls, text=''): """Create a horizontal divider with text at center.""" return cls(text, alignment=Qt.AlignCenter) @classmethod def vertical(cls): """Create a vertical divider""" return cls(orientation=Qt.Vertical)