mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
feat(utils/bec-designer): added startup script to launched QtDesigner compatible with conda environments
This commit is contained in:
17
bec_widgets/examples/plugin_example_pyside/main.py
Normal file
17
bec_widgets/examples/plugin_example_pyside/main.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
"""PySide6 port of the Qt Designer taskmenuextension example from Qt v6.x"""
|
||||
|
||||
import sys
|
||||
|
||||
from bec_ipython_client.main import BECIPythonClient
|
||||
from qtpy.QtWidgets import QApplication
|
||||
from tictactoe import TicTacToe
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
app = QApplication(sys.argv)
|
||||
window = TicTacToe()
|
||||
window.state = "-X-XO----"
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
@ -0,0 +1,12 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtDesigner import QPyDesignerCustomWidgetCollection
|
||||
from tictactoe import TicTacToe
|
||||
from tictactoeplugin import TicTacToePlugin
|
||||
|
||||
# Set PYSIDE_DESIGNER_PLUGINS to point to this directory and load the plugin
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(TicTacToePlugin())
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"files": ["tictactoe.py", "main.py", "registertictactoe.py", "tictactoeplugin.py",
|
||||
"tictactoetaskmenu.py"]
|
||||
}
|
135
bec_widgets/examples/plugin_example_pyside/tictactoe.py
Normal file
135
bec_widgets/examples/plugin_example_pyside/tictactoe.py
Normal file
@ -0,0 +1,135 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtCore import Property, QPoint, QRect, QSize, Qt, Slot
|
||||
from qtpy.QtGui import QPainter, QPen
|
||||
from qtpy.QtWidgets import QWidget
|
||||
|
||||
EMPTY = "-"
|
||||
CROSS = "X"
|
||||
NOUGHT = "O"
|
||||
DEFAULT_STATE = "---------"
|
||||
|
||||
|
||||
class TicTacToe(QWidget): # pragma: no cover
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._state = DEFAULT_STATE
|
||||
self._turn_number = 0
|
||||
|
||||
def minimumSizeHint(self):
|
||||
return QSize(200, 200)
|
||||
|
||||
def sizeHint(self):
|
||||
return QSize(200, 200)
|
||||
|
||||
def setState(self, new_state):
|
||||
self._turn_number = 0
|
||||
self._state = DEFAULT_STATE
|
||||
for position in range(min(9, len(new_state))):
|
||||
mark = new_state[position]
|
||||
if mark == CROSS or mark == NOUGHT:
|
||||
self._turn_number += 1
|
||||
self._change_state_at(position, mark)
|
||||
position += 1
|
||||
self.update()
|
||||
|
||||
def state(self):
|
||||
return self._state
|
||||
|
||||
@Slot()
|
||||
def clear_board(self):
|
||||
self._state = DEFAULT_STATE
|
||||
self._turn_number = 0
|
||||
self.update()
|
||||
|
||||
def _change_state_at(self, pos, new_state):
|
||||
self._state = self._state[:pos] + new_state + self._state[pos + 1 :]
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if self._turn_number == 9:
|
||||
self.clear_board()
|
||||
return
|
||||
for position in range(9):
|
||||
cell = self._cell_rect(position)
|
||||
if cell.contains(event.position().toPoint()):
|
||||
if self._state[position] == EMPTY:
|
||||
new_state = CROSS if self._turn_number % 2 == 0 else NOUGHT
|
||||
self._change_state_at(position, new_state)
|
||||
self._turn_number += 1
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
with QPainter(self) as painter:
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
|
||||
painter.setPen(QPen(Qt.darkGreen, 1))
|
||||
painter.drawLine(self._cell_width(), 0, self._cell_width(), self.height())
|
||||
painter.drawLine(2 * self._cell_width(), 0, 2 * self._cell_width(), self.height())
|
||||
painter.drawLine(0, self._cell_height(), self.width(), self._cell_height())
|
||||
painter.drawLine(0, 2 * self._cell_height(), self.width(), 2 * self._cell_height())
|
||||
|
||||
painter.setPen(QPen(Qt.darkBlue, 2))
|
||||
|
||||
for position in range(9):
|
||||
cell = self._cell_rect(position)
|
||||
if self._state[position] == CROSS:
|
||||
painter.drawLine(cell.topLeft(), cell.bottomRight())
|
||||
painter.drawLine(cell.topRight(), cell.bottomLeft())
|
||||
elif self._state[position] == NOUGHT:
|
||||
painter.drawEllipse(cell)
|
||||
|
||||
painter.setPen(QPen(Qt.yellow, 3))
|
||||
|
||||
for position in range(0, 8, 3):
|
||||
if (
|
||||
self._state[position] != EMPTY
|
||||
and self._state[position + 1] == self._state[position]
|
||||
and self._state[position + 2] == self._state[position]
|
||||
):
|
||||
y = self._cell_rect(position).center().y()
|
||||
painter.drawLine(0, y, self.width(), y)
|
||||
self._turn_number = 9
|
||||
|
||||
for position in range(3):
|
||||
if (
|
||||
self._state[position] != EMPTY
|
||||
and self._state[position + 3] == self._state[position]
|
||||
and self._state[position + 6] == self._state[position]
|
||||
):
|
||||
x = self._cell_rect(position).center().x()
|
||||
painter.drawLine(x, 0, x, self.height())
|
||||
self._turn_number = 9
|
||||
|
||||
if (
|
||||
self._state[0] != EMPTY
|
||||
and self._state[4] == self._state[0]
|
||||
and self._state[8] == self._state[0]
|
||||
):
|
||||
painter.drawLine(0, 0, self.width(), self.height())
|
||||
self._turn_number = 9
|
||||
|
||||
if (
|
||||
self._state[2] != EMPTY
|
||||
and self._state[4] == self._state[2]
|
||||
and self._state[6] == self._state[2]
|
||||
):
|
||||
painter.drawLine(0, self.height(), self.width(), 0)
|
||||
self._turn_number = 9
|
||||
|
||||
def _cell_rect(self, position):
|
||||
h_margin = self.width() / 30
|
||||
v_margin = self.height() / 30
|
||||
row = int(position / 3)
|
||||
column = position - 3 * row
|
||||
pos = QPoint(column * self._cell_width() + h_margin, row * self._cell_height() + v_margin)
|
||||
size = QSize(self._cell_width() - 2 * h_margin, self._cell_height() - 2 * v_margin)
|
||||
return QRect(pos, size)
|
||||
|
||||
def _cell_width(self):
|
||||
return self.width() / 3
|
||||
|
||||
def _cell_height(self):
|
||||
return self.height() / 3
|
||||
|
||||
state = Property(str, state, setState)
|
@ -0,0 +1,68 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtGui import QIcon
|
||||
from tictactoe import TicTacToe
|
||||
from tictactoetaskmenu import TicTacToeTaskMenuFactory
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
<widget class='TicTacToe' name='ticTacToe'>
|
||||
<property name='geometry'>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>200</width>
|
||||
<height>200</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name='state'>
|
||||
<string>-X-XO----</string>
|
||||
</property>
|
||||
</widget>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
|
||||
class TicTacToePlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._form_editor = None
|
||||
|
||||
def createWidget(self, parent):
|
||||
t = TicTacToe(parent)
|
||||
return t
|
||||
|
||||
def domXml(self):
|
||||
return DOM_XML
|
||||
|
||||
def group(self):
|
||||
return ""
|
||||
|
||||
def icon(self):
|
||||
return QIcon()
|
||||
|
||||
def includeFile(self):
|
||||
return "tictactoe"
|
||||
|
||||
def initialize(self, form_editor):
|
||||
self._form_editor = form_editor
|
||||
manager = form_editor.extensionManager()
|
||||
iid = TicTacToeTaskMenuFactory.task_menu_iid()
|
||||
manager.registerExtensions(TicTacToeTaskMenuFactory(manager), iid)
|
||||
|
||||
def isContainer(self):
|
||||
return False
|
||||
|
||||
def isInitialized(self):
|
||||
return self._form_editor is not None
|
||||
|
||||
def name(self):
|
||||
return "TicTacToe"
|
||||
|
||||
def toolTip(self):
|
||||
return "Tic Tac Toe Example, demonstrating class QDesignerTaskMenuExtension (Python)"
|
||||
|
||||
def whatsThis(self):
|
||||
return self.toolTip()
|
@ -0,0 +1,67 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtCore import Slot
|
||||
from qtpy.QtDesigner import QExtensionFactory, QPyDesignerTaskMenuExtension
|
||||
from qtpy.QtGui import QAction
|
||||
from qtpy.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout
|
||||
from tictactoe import TicTacToe
|
||||
|
||||
|
||||
class TicTacToeDialog(QDialog): # pragma: no cover
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
layout = QVBoxLayout(self)
|
||||
self._ticTacToe = TicTacToe(self)
|
||||
layout.addWidget(self._ticTacToe)
|
||||
button_box = QDialogButtonBox(
|
||||
QDialogButtonBox.Ok | QDialogButtonBox.Cancel | QDialogButtonBox.Reset
|
||||
)
|
||||
button_box.accepted.connect(self.accept)
|
||||
button_box.rejected.connect(self.reject)
|
||||
reset_button = button_box.button(QDialogButtonBox.Reset)
|
||||
reset_button.clicked.connect(self._ticTacToe.clear_board)
|
||||
layout.addWidget(button_box)
|
||||
|
||||
def set_state(self, new_state):
|
||||
self._ticTacToe.setState(new_state)
|
||||
|
||||
def state(self):
|
||||
return self._ticTacToe.state
|
||||
|
||||
|
||||
class TicTacToeTaskMenu(QPyDesignerTaskMenuExtension):
|
||||
def __init__(self, ticTacToe, parent):
|
||||
super().__init__(parent)
|
||||
self._ticTacToe = ticTacToe
|
||||
self._edit_state_action = QAction("Edit State...", None)
|
||||
self._edit_state_action.triggered.connect(self._edit_state)
|
||||
|
||||
def taskActions(self):
|
||||
return [self._edit_state_action]
|
||||
|
||||
def preferredEditAction(self):
|
||||
return self._edit_state_action
|
||||
|
||||
@Slot()
|
||||
def _edit_state(self):
|
||||
dialog = TicTacToeDialog(self._ticTacToe)
|
||||
dialog.set_state(self._ticTacToe.state)
|
||||
if dialog.exec() == QDialog.Accepted:
|
||||
self._ticTacToe.state = dialog.state()
|
||||
|
||||
|
||||
class TicTacToeTaskMenuFactory(QExtensionFactory):
|
||||
def __init__(self, extension_manager):
|
||||
super().__init__(extension_manager)
|
||||
|
||||
@staticmethod
|
||||
def task_menu_iid():
|
||||
return "org.qt-project.Qt.Designer.TaskMenu"
|
||||
|
||||
def createExtension(self, object, iid, parent):
|
||||
if iid != TicTacToeTaskMenuFactory.task_menu_iid():
|
||||
return None
|
||||
if object.__class__.__name__ != "TicTacToe":
|
||||
return None
|
||||
return TicTacToeTaskMenu(object, parent)
|
52
bec_widgets/utils/bec_designer.py
Normal file
52
bec_widgets/utils/bec_designer.py
Normal file
@ -0,0 +1,52 @@
|
||||
import os
|
||||
import sys
|
||||
import sysconfig
|
||||
from pathlib import Path
|
||||
|
||||
import bec_widgets
|
||||
|
||||
from PySide6.scripts.pyside_tool import (
|
||||
qt_tool_wrapper,
|
||||
ui_tool_binary,
|
||||
init_virtual_env,
|
||||
is_pyenv_python,
|
||||
is_virtual_env,
|
||||
_extend_path_var,
|
||||
)
|
||||
|
||||
|
||||
def patch_designer(): # pragma: no cover
|
||||
init_virtual_env()
|
||||
|
||||
major_version = sys.version_info[0]
|
||||
minor_version = sys.version_info[1]
|
||||
os.environ["PY_MAJOR_VERSION"] = str(major_version)
|
||||
os.environ["PY_MINOR_VERSION"] = str(minor_version)
|
||||
|
||||
if sys.platform == "linux":
|
||||
version = f"{major_version}.{minor_version}"
|
||||
library_name = f"libpython{version}{sys.abiflags}.so"
|
||||
if is_pyenv_python():
|
||||
library_name = str(Path(sysconfig.get_config_var("LIBDIR")) / library_name)
|
||||
os.environ["LD_PRELOAD"] = library_name
|
||||
elif sys.platform == "darwin":
|
||||
library_name = f"libpython{major_version}.{minor_version}.dylib"
|
||||
lib_path = str(Path(sysconfig.get_config_var("LIBDIR")) / library_name)
|
||||
os.environ["DYLD_INSERT_LIBRARIES"] = lib_path
|
||||
elif sys.platform == "win32":
|
||||
if is_virtual_env():
|
||||
_extend_path_var("PATH", os.fspath(Path(sys._base_executable).parent), True)
|
||||
|
||||
qt_tool_wrapper(ui_tool_binary("designer"), sys.argv[1:])
|
||||
|
||||
|
||||
# Patch the designer function
|
||||
def main(): # pragma: no cover
|
||||
os.environ["PYSIDE_DESIGNER_PLUGINS"] = os.path.join(
|
||||
os.path.dirname(bec_widgets.__file__), "examples/plugin_example_pyside"
|
||||
)
|
||||
patch_designer()
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
Reference in New Issue
Block a user