Fixed and updated Python integration (#127)

* FIX: Add Q_OS_MACOS flag to moc compiler.

* (Python) Demo and example from @n-elie.

* FIX: Addressing some sip files that were inconsistent with the header files.

* (Python) Addressing comments by @n-elie and switching to use WS_X11 for platform checks.

* (Python) Wrap definition of tFloatingWidgetBase to avoid 'Already Defined' error and fix include path for sip/linux/FloatingWidgetTitleBar.sip.

* Remove simple.py

* Fix case sensitive ui file loading in Linux

* Add windows case in get_moc_args

* Remove conda recipe

Co-authored-by: n-elie <40382614+n-elie@users.noreply.github.com>
This commit is contained in:
Hugo Slepicka 2020-02-24 22:22:51 -08:00 committed by GitHub
parent c90fb9413c
commit 8cc9cc25ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 426 additions and 349 deletions

View File

@ -1,36 +1,76 @@
import datetime import datetime
import logging import logging
import os
import sys
from PyQt5 import uic
from PyQt5.QtCore import (QCoreApplication, QDir, Qt, QSettings, QSignalBlocker, from PyQt5.QtCore import (QCoreApplication, QDir, Qt, QSettings, QSignalBlocker,
QRect) QRect, QPoint, qDebug, qInstallMessageHandler,
from PyQt5.QtGui import QGuiApplication QtDebugMsg, QtInfoMsg, QtWarningMsg,
QtCriticalMsg, QtFatalMsg)
from PyQt5.QtGui import (QGuiApplication, QIcon, QCloseEvent)
from PyQt5.QtWidgets import (QCalendarWidget, QFileSystemModel, QFrame, QLabel, from PyQt5.QtWidgets import (QCalendarWidget, QFileSystemModel, QFrame, QLabel,
QMenu, QTreeView, QAction, QWidgetAction, QMenu, QTreeView, QAction, QWidgetAction,
QComboBox, QStyle, QSizePolicy, QInputDialog) QComboBox, QStyle, QSizePolicy, QInputDialog, QMenu,
QToolButton, QWidget, QPlainTextEdit,
from PyQt5 import QtWidgets QTableWidget, QTableWidgetItem, QApplication,
QMessageBox)
try:
from PyQt5.QAxContainer import QAxWidget
except ImportError:
ACTIVEX_AVAILABLE = False
else:
ACTIVEX_AVAILABLE = True
from PyQtAds import QtAds from PyQtAds import QtAds
import rc # pyrcc5 demo.qrc -o rc.py
UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
class _State: class _State:
label_count = 0 label_count = 0
calendar_count = 0 calendar_count = 0
file_system_count = 0 file_system_count = 0
editor_count = 0
table_count = 0
activex_count = 0
def features_string(dock_widget: QtAds.CDockWidget) -> str:
'''Function returns a features string with closable (c), movable (m) and floatable (f)
features. i.e. The following string is for a not closable but movable and floatable
widget: c- m+ f+'''
f = dock_widget.features()
closable = f & QtAds.CDockWidget.DockWidgetClosable
movable = f & QtAds.CDockWidget.DockWidgetMovable
floatable = f &QtAds.CDockWidget.DockWidgetFloatable
return "c{} m{} f{}".format("+" if closable else "-",
"+" if movable else "-",
"+" if floatable else "-")
def append_feature_string_to_window_title(dock_widget: QtAds.CDockWidget):
'''Appends the string returned by features_string() to the window title of
the given DockWidget'''
dock_widget.setWindowTitle(dock_widget.windowTitle() + " ({})".format(features_string(dock_widget)))
def svg_icon(filename: str):
'''Helper function to create an SVG icon'''
# This is a workaround, because because in item views SVG icons are not
# properly scaled an look blurry or pixelate
icon = QIcon(filename)
icon.addPixmap(icon.pixmap(92))
return icon
def create_long_text_label_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget: def create_long_text_label_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
'''
Create long text label dock widget
Parameters
----------
view_menu : QMenu
Returns
-------
value : QtAds.CDockWidget
'''
label = QLabel() label = QLabel()
label.setWordWrap(True) label.setWordWrap(True)
label.setAlignment(Qt.AlignTop | Qt.AlignLeft) label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
@ -46,10 +86,9 @@ pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi.
Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu,
consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra
quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
'''.format(_State.label_count, str(datetime.datetime.now()))) '''.format(_State.label_count, datetime.datetime.now().strftime("%H:%M:%S:%f")))
_State.label_count += 1
dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count)) dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count))
_State.label_count += 1
dock_widget.setWidget(label) dock_widget.setWidget(label)
view_menu.addAction(dock_widget.toggleViewAction()) view_menu.addAction(dock_widget.toggleViewAction())
@ -57,39 +96,18 @@ quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
def create_calendar_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget: def create_calendar_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
'''
Create calendar dock widget
Parameters
----------
view_menu : QMenu
Returns
-------
value : QtAds.CDockWidget
'''
widget = QCalendarWidget() widget = QCalendarWidget()
dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count)) dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count))
_State.calendar_count += 1 _State.calendar_count += 1
dock_widget.setWidget(widget) dock_widget.setWidget(widget)
dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow) dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow)
dock_widget.setIcon(svg_icon(":/adsdemo/images/date_range.svg"))
view_menu.addAction(dock_widget.toggleViewAction()) view_menu.addAction(dock_widget.toggleViewAction())
return dock_widget return dock_widget
def create_file_system_tree_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget: def create_file_system_tree_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
'''
Create file system tree dock widget
Parameters
----------
view_menu : QMenu
Returns
-------
value : QtAds.CDockWidget
'''
widget = QTreeView() widget = QTreeView()
widget.setFrameShape(QFrame.NoFrame) widget.setFrameShape(QFrame.NoFrame)
@ -104,7 +122,78 @@ def create_file_system_tree_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
return dock_widget return dock_widget
class MainWindow(QtWidgets.QMainWindow): def create_editor_widget(view_menu: QMenu) -> QtAds.CDockWidget:
widget = QPlainTextEdit()
widget.setPlaceholderText("This is an editor. If you close the editor, it will be "
"deleted. Enter your text here.")
widget.setStyleSheet("border: none")
dock_widget = QtAds.CDockWidget("Editor {}".format(_State.editor_count))
_State.editor_count += 1
dock_widget.setWidget(widget)
dock_widget.setIcon(svg_icon(":/adsdemo/images/edit.svg"))
dock_widget.setFeature(QtAds.CDockWidget.CustomCloseHandling, True)
view_menu.addAction(dock_widget.toggleViewAction())
options_menu = QMenu(dock_widget)
options_menu.setTitle("Options")
options_menu.setToolTip(options_menu.title())
options_menu.setIcon(svg_icon(":/adsdemo/images/custom-menu-button.svg"))
menu_action = options_menu.menuAction()
# The object name of the action will be set for the QToolButton that
# is created in the dock area title bar. You can use this name for CSS
# styling
menu_action.setObjectName("options_menu")
dock_widget.setTitleBarActions([options_menu.menuAction()])
a = options_menu.addAction("Clear Editor")
a.triggered.connect(widget.clear)
return dock_widget
def create_table_widget(view_menu: QMenu) -> QtAds.CDockWidget:
widget = QTableWidget()
dock_widget = QtAds.CDockWidget("Table {}".format(_State.table_count))
_State.table_count += 1
COLCOUNT = 5
ROWCOUNT = 30
widget.setColumnCount(COLCOUNT)
widget.setRowCount(ROWCOUNT)
for col in range(ROWCOUNT):
widget.setHorizontalHeaderItem(col, QTableWidgetItem("Col {}".format(col+1)))
for row in range(ROWCOUNT):
widget.setItem(row, col, QTableWidgetItem("T {:}-{:}".format(row+1, col+1)))
dock_widget.setWidget(widget)
dock_widget.setIcon(svg_icon(":/adsdemo/images/grid_on.svg"))
view_menu.addAction(dock_widget.toggleViewAction())
return dock_widget
if ACTIVEX_AVAILABLE:
def create_activex_widget(view_menu: QMenu, parent: QWidget = None) -> QtAds.CDockWidget:
widget = QAxWidget("{6bf52a52-394a-11d3-b153-00c04f79faa6}", parent)
dock_widget = QtAds.CDockWidget("Active X {}".format(_State.activex_count))
_State.activex_count += 1
dock_widget.setWidget(widget)
view_menu.addAction(dock_widget.toggleViewAction())
return dock_widget
class CustomComponentsFactory(QtAds.CDockComponentsFactory):
def createDockAreaTitleBar(self, dock_area: QtAds.CDockAreaWidget) -> QtAds.CDockAreaTitleBar:
title_bar = QtAds.CDockAreaTitleBar(dock_area)
custom_button = QToolButton(dock_area)
custom_button.setToolTip("Help")
custom_button.setIcon(svg_icon(":/adsdemo/images/help_outline.svg"))
custom_button.setAutoRaise(True)
index = title_bar.indexOf(title_bar.button(QtAds.TitleBarButtonTabsMenu))
title_bar.insertWidget(index + 1, custom_button)
return title_bar
class MainWindow(MainWindowUI, MainWindowBase):
save_perspective_action: QAction save_perspective_action: QAction
perspective_list_action: QWidgetAction perspective_list_action: QWidgetAction
perspective_combo_box: QComboBox perspective_combo_box: QComboBox
@ -117,111 +206,101 @@ class MainWindow(QtWidgets.QMainWindow):
self.perspective_combo_box = None self.perspective_combo_box = None
self.dock_manager = None self.dock_manager = None
self.setup_ui() self.setupUi(self)
self.dock_manager = QtAds.CDockManager(self)
self.perspective_combo_box.activated[str].connect(self.dock_manager.openPerspective)
self.create_content()
self.resize(800, 600)
self.restore_state()
self.restore_perspectives()
def setup_ui(self):
self.setObjectName("MainWindow")
self.resize(400, 300)
self.setDockOptions(QtWidgets.QMainWindow.AllowTabbedDocks)
self.centralWidget = QtWidgets.QWidget(self)
self.centralWidget.setObjectName("centralWidget")
self.setCentralWidget(self.centralWidget)
self.status_bar = QtWidgets.QStatusBar(self)
self.status_bar.setObjectName("statusBar")
self.setStatusBar(self.status_bar)
self.menu_bar = QtWidgets.QMenuBar(self)
self.menu_bar.setGeometry(QRect(0, 0, 400, 21))
self.menu_bar.setObjectName("menuBar")
self.menu_file = QtWidgets.QMenu(self.menu_bar)
self.menu_file.setObjectName("menuFile")
self.menu_view = QtWidgets.QMenu(self.menu_bar)
self.menu_view.setObjectName("menuView")
self.menu_about = QtWidgets.QMenu(self.menu_bar)
self.menu_about.setObjectName("menuAbout")
self.setMenuBar(self.menu_bar)
self.tool_bar = QtWidgets.QToolBar(self)
self.tool_bar.setObjectName("toolBar")
self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
self.action_exit = QtWidgets.QAction(self)
self.action_exit.setObjectName("actionExit")
self.action_save_state = QtWidgets.QAction(self)
self.action_save_state.setObjectName("actionSaveState")
self.action_save_state.triggered.connect(self.saveState)
self.action_restore_state = QtWidgets.QAction(self)
self.action_restore_state.setObjectName("actionRestoreState")
self.action_restore_state.triggered.connect(self.restore_state)
self.menu_file.addAction(self.action_exit)
self.menu_file.addAction(self.action_save_state)
self.menu_file.addAction(self.action_restore_state)
self.menu_bar.addAction(self.menu_file.menuAction())
self.menu_bar.addAction(self.menu_view.menuAction())
self.menu_bar.addAction(self.menu_about.menuAction())
self.setWindowTitle("MainWindow")
self.menu_file.setTitle("File")
self.menu_view.setTitle("View")
self.menu_about.setTitle("About")
self.tool_bar.setWindowTitle("toolBar")
self.action_exit.setText("Exit")
self.action_save_state.setText("Save State")
self.action_restore_state.setText("Restore State")
self.create_actions() self.create_actions()
def create_actions(self): # uncomment the following line if the tab close button should be
''' # a QToolButton instead of a QPushButton
Creates the toolbar actions # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.configFlags() | QtAds.CDockManager.TabCloseButtonIsToolButton)
'''
self.tool_bar.addAction(self.action_save_state)
self.action_save_state.setIcon(self.style().standardIcon(QStyle.SP_DialogSaveButton))
self.tool_bar.addAction(self.action_restore_state)
self.action_restore_state.setIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton))
self.save_perspective_action = QAction("Save Perspective", self)
self.save_perspective_action.triggered.connect(self.save_perspective)
self.perspective_list_action = QWidgetAction(self) # uncomment the following line if you want a fixed tab width that does
self.perspective_combo_box = QComboBox(self) # not change if the visibility of the close button changes
self.perspective_combo_box.setSizeAdjustPolicy(QComboBox.AdjustToContents) # QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.RetainTabSizeWhenCloseButtonHidden, True)
self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
self.perspective_list_action.setDefaultWidget(self.perspective_combo_box) # uncomment the follwing line if you want to use non opaque undocking and splitter
self.tool_bar.addSeparator() # movements
self.tool_bar.addAction(self.perspective_list_action) # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DefaultNonOpaqueConfig)
self.tool_bar.addAction(self.save_perspective_action)
# Now create the dock manager and its content
self.dock_manager = QtAds.CDockManager(self)
# Uncomment the following line to have the old style where the dock
# area close button closes the active tab
# QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DockAreaHasCloseButton
# | QtAds.CDockManager.DockAreaCloseButtonClosesTab)
self.perspective_combo_box.activated[str].connect(self.dock_manager.openPerspective)
self.create_content()
# Default window geometry - center on screen
self.resize(1280, 720)
self.setGeometry(QStyle.alignedRect(
Qt.LeftToRight, Qt.AlignCenter, self.frameSize(),
QGuiApplication.primaryScreen().availableGeometry()))
# self.restore_state()
self.restore_perspectives()
def create_content(self): def create_content(self):
'''
Fill the dock manager with dock widgets
'''
# Test container docking # Test container docking
view_menu = self.menu_view view_menu = self.menuView
dock_widget = create_calendar_dock_widget(view_menu) dock_widget = create_calendar_dock_widget(view_menu)
dock_widget.setIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton))
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
special_dock_area = self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget)
# For this Special Dock Area we want to avoid dropping on the center of it (i.e. we don't want this widget to be ever tabbified):
special_dock_area.setAllowedAreas(QtAds.OuterDockAreas)
# special_dock_area.setAllowedAreas(QtAds.LeftDockWidgetArea | QtAds.RightDockWidgetArea) # just for testing
self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, create_long_text_label_dock_widget(view_menu)) self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, create_long_text_label_dock_widget(view_menu))
file_system_widget = create_file_system_tree_dock_widget(view_menu) file_system_widget = create_file_system_tree_dock_widget(view_menu)
tool_bar = file_system_widget.createDefaultToolBar() tool_bar = file_system_widget.createDefaultToolBar()
tool_bar.addAction(self.action_save_state) tool_bar.addAction(self.actionSaveState)
tool_bar.addAction(self.action_restore_state) tool_bar.addAction(self.actionRestoreState)
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
append_feature_string_to_window_title(file_system_widget)
self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget) self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget)
file_system_widget = create_file_system_tree_dock_widget(view_menu) file_system_widget = create_file_system_tree_dock_widget(view_menu)
tool_bar = file_system_widget.createDefaultToolBar() tool_bar = file_system_widget.createDefaultToolBar()
tool_bar.addAction(self.action_save_state) tool_bar.addAction(self.actionSaveState)
tool_bar.addAction(self.action_restore_state) tool_bar.addAction(self.actionRestoreState)
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False) file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
append_feature_string_to_window_title(file_system_widget)
# Test custom factory - we inject a help button into the title bar
self.factory = CustomComponentsFactory()
QtAds.CDockComponentsFactory.setFactory(self.factory)
top_dock_area = self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, file_system_widget) top_dock_area = self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, file_system_widget)
QtAds.CDockComponentsFactory.resetDefaultFactory()
# We create a calendar widget and clear all flags to prevent the dock area
# from closing
dock_widget = create_calendar_dock_widget(view_menu) dock_widget = create_calendar_dock_widget(view_menu)
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna") dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area) dock_area = self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area)
# Now we add a custom button to the dock area title bar that will create
# new editor widgets when clicked
custom_button = QToolButton(dock_area)
custom_button.setToolTip("Create Editor")
custom_button.setIcon(svg_icon(":/adsdemo/images/plus.svg"))
custom_button.setAutoRaise(True)
title_bar = dock_area.titleBar()
index = title_bar.indexOf(title_bar.tabBar())
title_bar.insertWidget(index + 1, custom_button)
def on_button_clicked():
dock_widget = create_editor_widget(self.menuView)
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
self.dock_manager.addDockWidgetTabToArea(dock_widget, dock_area)
dock_widget.closeRequested.connect(self.on_editor_close_requested)
custom_button.clicked.connect(on_button_clicked)
# Test dock area docking # Test dock area docking
right_dock_area = self.dock_manager.addDockWidget( right_dock_area = self.dock_manager.addDockWidget(
@ -236,12 +315,113 @@ class MainWindow(QtWidgets.QMainWindow):
create_long_text_label_dock_widget(view_menu), right_dock_area) create_long_text_label_dock_widget(view_menu), right_dock_area)
self.dock_manager.addDockWidget( self.dock_manager.addDockWidget(
QtAds.RightDockWidgetArea, QtAds.CenterDockWidgetArea,
create_long_text_label_dock_widget(view_menu), right_dock_area) create_long_text_label_dock_widget(view_menu), right_dock_area)
self.dock_manager.addDockWidget( self.dock_manager.addDockWidget(
QtAds.CenterDockWidgetArea, QtAds.CenterDockWidgetArea,
create_long_text_label_dock_widget(view_menu), bottom_dock_area) create_long_text_label_dock_widget(view_menu), bottom_dock_area)
action = self.menuView.addAction("Set {} floating".format(dock_widget.windowTitle()))
action.triggered.connect(dock_widget.setFloating)
if ACTIVEX_AVAILABLE:
flags = self.dock_manager.configFlags()
if flags & QtAds.CDockManager.OpaqueUndocking:
self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea,
create_activex_widget(view_menu), right_dock_area)
for dock_widget in self.dock_manager.dockWidgetsMap().values():
dock_widget.viewToggled.connect(self.on_view_toggled)
dock_widget.visibilityChanged.connect(self.on_view_visibility_changed)
def create_actions(self):
self.toolBar.addAction(self.actionSaveState)
self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.actionSaveState.setIcon(svg_icon(":/adsdemo/images/save.svg"))
self.toolBar.addAction(self.actionRestoreState)
self.actionRestoreState.setIcon(svg_icon(":/adsdemo/images/restore.svg"))
self.save_perspective_action = QAction("Create Perspective", self)
self.save_perspective_action.setIcon(svg_icon(":/adsdemo/images/picture_in_picture.svg"))
self.save_perspective_action.triggered.connect(self.save_perspective)
self.perspective_list_action = QWidgetAction(self)
self.perspective_combo_box = QComboBox(self)
self.perspective_combo_box.setSizeAdjustPolicy(QComboBox.AdjustToContents)
self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
self.perspective_list_action.setDefaultWidget(self.perspective_combo_box)
self.toolBar.addSeparator()
self.toolBar.addAction(self.perspective_list_action)
self.toolBar.addAction(self.save_perspective_action)
a = self.toolBar.addAction("Create Editor")
a.setToolTip("Creates floating dynamic dockable editor windows that are deleted on close")
a.setIcon(svg_icon(":/adsdemo/images/note_add.svg"))
a.triggered.connect(self.create_editor)
a = self.toolBar.addAction("Create Table")
a.setToolTip("Creates floating dynamic dockable table with millions of entries")
a.setIcon(svg_icon(":/adsdemo/images/grid_on.svg"))
a.triggered.connect(self.create_table)
def closeEvent(self, event: QCloseEvent):
self.save_state()
super().closeEvent(event)
def on_action_save_state_triggered(state: bool):
qDebug("MainWindow::on_action_save_state_triggered")
self.save_state()
def on_action_restore_state_triggered(state: bool):
qDebug("MainWindow::on_action_restore_state_triggered")
self.restore_state()
def save_perspective(self):
perspective_name, ok = QInputDialog.getText(self, "Save perspective",
"Enter unique name:")
if ok and perspective_name:
self.dock_manager.addPerspective(perspective_name)
_ = QSignalBlocker(self.perspective_combo_box)
self.perspective_combo_box.clear()
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
self.perspective_combo_box.setCurrentText(perspective_name)
self.save_perspectives()
def on_view_toggled(self, open: bool):
dock_widget = self.sender()
if dock_widget is None:
return
qDebug("{} view_toggled({})".format(dock_widget.objectName(), open))
def on_view_visibility_changed(self, visible: bool):
dock_widget = self.sender()
if dock_widget is None:
return
qDebug("{} visibility_changed({})".format(dock_widget.objectName(), visible))
def create_editor(self):
dock_widget = create_editor_widget(self.menuView)
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget)
floating_widget.move(QPoint(20, 20))
dock_widget.closeRequested.connect(self.on_editor_close_requested)
def on_editor_close_requested(self):
dock_widget = self.sender()
result = QMessageBox.question(self, "Close Editor",
"Editor {} contains unsaved changes? Would you like to close it?".format(dock_widget.windowTitle()))
if result == QMessageBox.Yes:
dock_widget.closeDockWidget()
def create_table(self):
dock_widget = create_table_widget(self.menuView)
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget)
floating_widget.move(QPoint(40, 40))
def save_state(self): def save_state(self):
''' '''
Saves the dock manager state and the main window geometry Saves the dock manager state and the main window geometry
@ -251,13 +431,6 @@ class MainWindow(QtWidgets.QMainWindow):
settings.setValue("mainWindow/State", self.saveState()) settings.setValue("mainWindow/State", self.saveState())
settings.setValue("mainWindow/DockingState", self.dock_manager.saveState()) settings.setValue("mainWindow/DockingState", self.dock_manager.saveState())
def save_perspectives(self):
'''
Save the list of perspectives
'''
settings = QSettings("Settings.ini", QSettings.IniFormat)
self.dock_manager.savePerspectives(settings)
def restore_state(self): def restore_state(self):
''' '''
Restores the dock manager state Restores the dock manager state
@ -275,6 +448,13 @@ class MainWindow(QtWidgets.QMainWindow):
if state is not None: if state is not None:
self.dock_manager.restore_state(state) self.dock_manager.restore_state(state)
def save_perspectives(self):
'''
Save the list of perspectives
'''
settings = QSettings("Settings.ini", QSettings.IniFormat)
self.dock_manager.savePerspectives(settings)
def restore_perspectives(self): def restore_perspectives(self):
''' '''
Restore the perspective listo of the dock manager Restore the perspective listo of the dock manager
@ -295,22 +475,31 @@ class MainWindow(QtWidgets.QMainWindow):
self.save_perspectives() self.save_perspectives()
def main(app_): def my_message_output(type, context, msg):
main_window = MainWindow() if type == QtDebugMsg:
main_window.show() print("Debug: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
state = main_window.dock_manager.saveState() elif type == QtInfoMsg:
# print('This is what the saved state looks like in XML:') print("Info: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
# print(str(state, 'utf-8')) elif type == QtWarningMsg:
# print() print("Warning: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
# main_window.dock_manager.restore_state(state) elif type == QtCriticalMsg:
return main_window print("Critical: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
elif type == QtFatalMsg:
print("Fatal: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
if __name__ == '__main__': if __name__ == '__main__':
# logging.basicConfig(level='DEBUG')
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling) QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QtWidgets.QApplication([]) app = QApplication(sys.argv)
window = main(app) app.setQuitOnLastWindowClosed(True)
window.show()
with open(os.path.join(os.path.dirname(__file__), "app.css"), "r") as style_sheet_file:
app.setStyleSheet(style_sheet_file.read())
qInstallMessageHandler(my_message_output)
qDebug("Message handler test")
mw = MainWindow()
mw.show()
app.exec_() app.exec_()

52
example/example.py Normal file
View File

@ -0,0 +1,52 @@
import datetime
import logging
import os
import sys
from PyQt5 import uic
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QLabel
from PyQtAds import QtAds
UI_FILE = os.path.join(os.path.dirname(__file__), 'MainWindow.ui')
MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
class MainWindow(MainWindowUI, MainWindowBase):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
# Create the dock manager. Because the parent parameter is a QMainWindow
# the dock manager registers itself as the central widget.
self.dock_manager = QtAds.CDockManager(self)
# Create example content label - this can be any application specific
# widget
l = QLabel()
l.setWordWrap(True)
l.setAlignment(Qt.AlignTop | Qt.AlignLeft);
l.setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
# Create a dock widget with the title Label 1 and set the created label
# as the dock widget content
dock_widget = QtAds.CDockWidget("Label 1")
dock_widget.setWidget(l)
# Add the toggleViewAction of the dock widget to the menu to give
# the user the possibility to show the dock widget if it has been closed
self.menuView.addAction(dock_widget.toggleViewAction())
# Add the dock widget to the top dock widget area
self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, dock_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()

View File

@ -1,41 +0,0 @@
{% set data = load_setup_py_data() %}
package:
name: pyqtads
version: {{ data.get('version') }}
source:
path: ../
build:
number: 0
script: python setup.py install --single-version-externally-managed --record=record.txt --conda-recipe
requirements:
build:
- python
- setuptools
- pyqt>=5.9
- sip>=4.19
run:
- python
- pyqt>=5.9
- sip>=4.19
- pywin32 [win]
test:
imports:
- PyQtAds
about:
home: {{ data.get('url') }}
license: {{ data.get('license') }}
license_family: LGPL
license_file: 'LICENSE.md'
summary: {{ data.get('description') }}
description: {{ data.get('description') }}
doc_url: ''
dev_url: {{ data.get('url') }}
extra:
recipe-maintainers: 'nicolas.elie@cnrs.fr'

View File

@ -201,6 +201,10 @@ class build_ext(sipdistutils.build_ext):
def get_moc_args(out_file, source): def get_moc_args(out_file, source):
if sys.platform.startswith('linux'): if sys.platform.startswith('linux'):
return ["moc", "-D", "Q_OS_LINUX=1", "-o", out_file, source] return ["moc", "-D", "Q_OS_LINUX=1", "-o", out_file, source]
if sys.platform.startswith('darwin'):
return ["moc", "-D", "Q_OS_MACOS=1", "-o", out_file, source]
if sys.platform.startswith('win'):
return ["moc", "-D", "Q_OS_WIN=1", "-o", out_file, source]
return ["moc", "-o", out_file, source] return ["moc", "-o", out_file, source]
# Run moc on all header files. # Run moc on all header files.

View File

@ -1,82 +0,0 @@
import logging
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import Qt
from PyQtAds import QtAds
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setup_ui()
self.dock_manager = QtAds.CDockManager(self)
self.dock_widgets = []
for label_text, area in (
('1 Top', QtAds.TopDockWidgetArea),
('2 Bottom', QtAds.BottomDockWidgetArea),
('3 Left', QtAds.LeftDockWidgetArea),
('4 Right', QtAds.RightDockWidgetArea),
):
# Create example content label - this can be any application specific
# widget
label = QtWidgets.QLabel()
label.setWordWrap(True)
label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
label.setText(f"{label_text}: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
# Create a dock widget with the title Label 1 and set the created label
# as the dock widget content
dock_widget = QtAds.CDockWidget(label_text)
dock_widget.setWidget(label)
self.dock_widgets.append(dock_widget)
# Add the toggleViewAction of the dock widget to the menu to give
# the user the possibility to show the dock widget if it has been closed
self.menu_view.addAction(dock_widget.toggleViewAction())
# Add the dock widget to the top dock widget area
self.dock_manager.addDockWidget(area, dock_widget)
def setup_ui(self):
self.setWindowTitle("MainWindow")
self.setObjectName("MainWindow")
self.resize(400, 300)
self.central_widget = QtWidgets.QWidget(self)
self.central_widget.setObjectName("central_widget")
self.setCentralWidget(self.central_widget)
self.menu_bar = QtWidgets.QMenuBar(self)
self.menu_bar.setGeometry(QtCore.QRect(0, 0, 400, 21))
self.menu_bar.setObjectName("menuBar")
self.menu_view = QtWidgets.QMenu(self.menu_bar)
self.menu_view.setObjectName("menu_view")
self.menu_view.setTitle("View")
self.setMenuBar(self.menu_bar)
self.status_bar = QtWidgets.QStatusBar(self)
self.status_bar.setObjectName("statusBar")
self.setStatusBar(self.status_bar)
self.menu_bar.addAction(self.menu_view.menuAction())
def main(app):
main = MainWindow()
main.show()
state = main.dock_manager.saveState()
print('This is what the saved state looks like in XML:')
print(state)
print()
main.dock_manager.restoreState(state)
return main
if __name__ == '__main__':
logging.basicConfig(level='DEBUG')
app = QtWidgets.QApplication([])
window = main(app)
window.show()
print('shown')
app.exec_()

View File

@ -134,6 +134,8 @@ protected:
ads::CDockOverlay* containerOverlay() const; ads::CDockOverlay* containerOverlay() const;
ads::CDockOverlay* dockAreaOverlay() const; ads::CDockOverlay* dockAreaOverlay() const;
virtual void showEvent(QShowEvent *event);
public: public:
enum eViewMenuInsertionOrder enum eViewMenuInsertionOrder
{ {

View File

@ -27,6 +27,7 @@ public:
ads::DockWidgetArea showOverlay(QWidget* target); ads::DockWidgetArea showOverlay(QWidget* target);
void hideOverlay(); void hideOverlay();
void enableDropPreview(bool Enable); void enableDropPreview(bool Enable);
bool dropPreviewEnabled() const;
QRect dropOverlayRect() const; QRect dropOverlayRect() const;
virtual bool event(QEvent *e); virtual bool event(QEvent *e);
@ -58,6 +59,8 @@ protected:
void setIconOverlayColor(const QColor& Color); void setIconOverlayColor(const QColor& Color);
void setIconArrowColor(const QColor& Color); void setIconArrowColor(const QColor& Color);
void setIconShadowColor(const QColor& Color); void setIconShadowColor(const QColor& Color);
virtual void showEvent(QShowEvent* e);
void setAreaWidgets(const QHash<ads::DockWidgetArea, QWidget*>& widgets);
public: public:
CDockOverlayCross(ads::CDockOverlay* overlay /TransferThis/); CDockOverlayCross(ads::CDockOverlay* overlay /TransferThis/);

View File

@ -30,6 +30,8 @@ public:
DockWidgetMovable, DockWidgetMovable,
DockWidgetFloatable, DockWidgetFloatable,
DockWidgetDeleteOnClose, DockWidgetDeleteOnClose,
CustomCloseHandling,
DefaultDockWidgetFeatures,
AllDockWidgetFeatures, AllDockWidgetFeatures,
NoDockWidgetFeatures NoDockWidgetFeatures
}; };
@ -83,6 +85,9 @@ public:
Qt::ToolButtonStyle toolBarStyle(ads::CDockWidget::eState State) const; Qt::ToolButtonStyle toolBarStyle(ads::CDockWidget::eState State) const;
void setToolBarIconSize(const QSize& IconSize, ads::CDockWidget::eState State); void setToolBarIconSize(const QSize& IconSize, ads::CDockWidget::eState State);
QSize toolBarIconSize(eState State) const; QSize toolBarIconSize(eState State) const;
void setTitleBarActions(QList<QAction*> actions);
virtual QList<QAction*> titleBarActions() const;
void setTabToolTip(const QString &text); void setTabToolTip(const QString &text);
public: public:
@ -92,12 +97,14 @@ public slots:
void toggleView(bool Open = true); void toggleView(bool Open = true);
void setFloating(); void setFloating();
void deleteDockWidget(); void deleteDockWidget();
void closeDockWidget();
signals: signals:
void viewToggled(bool Open); void viewToggled(bool Open);
void closed(); void closed();
void titleChanged(const QString& Title); void titleChanged(const QString& Title);
void topLevelChanged(bool topLevel); void topLevelChanged(bool topLevel);
void closeRequested();
void visibilityChanged(bool visible); void visibilityChanged(bool visible);
void featuresChanged(ads::CDockWidget::DockWidgetFeatures features); void featuresChanged(ads::CDockWidget::DockWidgetFeatures features);
}; };

View File

@ -23,9 +23,9 @@ public:
virtual ~CDockWidgetTab(); virtual ~CDockWidgetTab();
bool isActiveTab() const; bool isActiveTab() const;
void setActiveTab(bool active); void setActiveTab(bool active);
ads::CDockWidget* dockWidget() const;
void setDockAreaWidget(ads::CDockAreaWidget* DockArea /Transfer/); void setDockAreaWidget(ads::CDockAreaWidget* DockArea /Transfer/);
ads::CDockAreaWidget* dockAreaWidget() const; ads::CDockAreaWidget* dockAreaWidget() const;
ads::CDockWidget* dockWidget() const;
void setIcon(const QIcon& Icon); void setIcon(const QIcon& Icon);
const QIcon& icon() const; const QIcon& icon() const;
QString text() const; QString text() const;

View File

@ -5,6 +5,13 @@
%If (Qt_5_0_0 -) %If (Qt_5_0_0 -)
%If (WS_X11)
typedef QDockWidget tFloatingWidgetBase;
%End
%If (!WS_X11)
typedef QWidget tFloatingWidgetBase;
%End
namespace ads namespace ads
{ {
@ -23,7 +30,7 @@ public:
}; };
class CFloatingDockContainer : QWidget, ads::IFloatingWidget class CFloatingDockContainer : tFloatingWidgetBase, ads::IFloatingWidget
{ {
%TypeHeaderCode %TypeHeaderCode

View File

@ -1,7 +1,6 @@
%Module(name=PyQtAds.QtAds.ads, call_super_init=True, keyword_arguments="Optional", use_limited_api=True) %Module(name=PyQtAds.QtAds.ads, call_super_init=True, keyword_arguments="Optional", use_limited_api=True)
%Import QtCore/QtCoremod.sip %Import QtCore/QtCoremod.sip
%DefaultSupertype sip.simplewrapper %DefaultSupertype sip.simplewrapper
%Platforms {Linux macOS Windows}
%Include ads_globals.sip %Include ads_globals.sip
%Include DockWidget.sip %Include DockWidget.sip
@ -16,12 +15,9 @@
%Include DockSplitter.sip %Include DockSplitter.sip
%Include DockWidgetTab.sip %Include DockWidgetTab.sip
%Include ElidingLabel.sip %Include ElidingLabel.sip
%Include FloatingDockContainer.sip
%Include FloatingDragPreview.sip %Include FloatingDragPreview.sip
%Include IconProvider.sip %Include IconProvider.sip
%If (Linux) %If (WS_X11)
%Include linux/FloatingDockContainer.sip
%Include linux/FloatingWidgetTitleBar.sip %Include linux/FloatingWidgetTitleBar.sip
%End %End
%If (!Linux)
%Include FloatingDockContainer.sip
%End

View File

@ -8,6 +8,13 @@ namespace ads
#include <ads_globals.h> #include <ads_globals.h>
%End %End
enum eStateFileVersion
{
InitialVerison,
Version1,
CurrentVersion
};
enum DockWidgetArea enum DockWidgetArea
{ {
NoDockWidgetArea, NoDockWidgetArea,

View File

@ -1,67 +0,0 @@
// NOTE: this is the Linux version, with QDockWidget as the
// CFloatingDockContainer base class.
%Import QtWidgets/QtWidgetsmod.sip
%If (Qt_5_0_0 -)
namespace ads
{
class IFloatingWidget
{
%TypeHeaderCode
#include <FloatingDockContainer.h>
%End
public:
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
ads::eDragState DragState, QWidget* MouseEventHandler) = 0;
virtual void moveFloating() = 0;
virtual void finishDragging() = 0;
};
class CFloatingDockContainer : QDockWidget, ads::IFloatingWidget
{
%TypeHeaderCode
#include <FloatingDockContainer.h>
%End
protected:
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
ads::eDragState DragState, QWidget* MouseEventHandler);
void startDragging(const QPoint& DragStartMousePos, const QSize& Size,
QWidget* MouseEventHandler);
virtual void finishDragging();
void initFloatingGeometry(const QPoint& DragStartMousePos, const QSize& Size);
void moveFloating();
bool restoreState(ads::CDockingStateReader& Stream, bool Testing);
void updateWindowTitle();
protected:
virtual void changeEvent(QEvent *event);
virtual void moveEvent(QMoveEvent *event);
virtual bool event(QEvent *e);
virtual void closeEvent(QCloseEvent *event);
virtual void hideEvent(QHideEvent *event);
virtual void showEvent(QShowEvent *event);
public:
CFloatingDockContainer(ads::CDockManager* DockManager /TransferThis/);
CFloatingDockContainer(ads::CDockAreaWidget* DockArea /TransferThis/);
CFloatingDockContainer(ads::CDockWidget* DockWidget /TransferThis/);
virtual ~CFloatingDockContainer();
ads::CDockContainerWidget* dockContainer() const;
bool isClosable() const;
bool hasTopLevelDockWidget() const;
ads::CDockWidget* topLevelDockWidget() const;
QList<ads::CDockWidget*> dockWidgets() const;
};
};
%End

View File

@ -5,7 +5,7 @@
namespace ads namespace ads
{ {
%TypeHeaderCode %TypeHeaderCode
#include <FloatingWidgetTitleBar.h> #include <linux/FloatingWidgetTitleBar.h>
%End %End
class CFloatingWidgetTitleBar : QWidget class CFloatingWidgetTitleBar : QWidget