-
Notifications
You must be signed in to change notification settings - Fork 459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python scripted interface #621
Conversation
@jcfr: Would you mind reviewing ? |
bd57d3b
to
7ffa833
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for improving util module and adding test.
Very minor nitpick: After removing the extra spaces, LGTM
background=backgroundNode, | ||
foreground=foregroundNode, | ||
label=labelmapNode, | ||
foregroundOpacity= 0.5, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra space
foreground=foregroundNode, | ||
label=labelmapNode, | ||
foregroundOpacity= 0.5, | ||
labelOpacity= 0.1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra space
background=otherBackgroundNode.GetID(), | ||
foreground=otherForegroundNode.GetID(), | ||
label=otherLabelmapNode.GetID(), | ||
foregroundOpacity= 0.0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space
@@ -292,6 +292,7 @@ if(Slicer_USE_QtTesting AND Slicer_USE_PYTHONQT) | |||
slicer_add_python_unittest(SCRIPT Charting.py) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in commit message, devellopers -> developers
super(QtWidgetMixin, self).__init__() | ||
self.Widget = None | ||
|
||
def loadUI(self, path, fail_silently=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Convert comment to python docstring
# Attempts to load and return a ui file that the given path points to.
# This method will raise an AssertionError if the ui file cannot be
# loaded and fail_silently is False (default)
->
Load UI file ``path`` and return the corresponding widget.
Raises a ``RuntimeError`` exception if the UI file is not found or if no widget was instantiated.
loader = qt.QUiLoader() | ||
widget = loader.load(qfile) | ||
if not fail_silently and not widget: | ||
errorMessage = "Could not load UI file: " + str(path) + "\n\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to keep the method simple and always throw a RuntimeError
raise AssertionError(errorMessage) | ||
return widget | ||
|
||
def get(self, name): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
convert to python docstring
|
||
def get(self, name): | ||
# Convenience method to access a widget from the self.Widget attribute. | ||
# This method will throw an AssertionError exception if the widget with the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AssertionError
-> RuntimeError
class QtWidgetMixin(object): | ||
def __init__(self): | ||
super(QtWidgetMixin, self).__init__() | ||
self.Widget = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not set anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean self.Widget
? This is used in the get() method. But yes, it is left to the user to be set.
(See my comment about the get()
method).
widget = loader.load(qfile) | ||
if not fail_silently and not widget: | ||
errorMessage = "Could not load UI file: " + str(path) + "\n\n" | ||
raise AssertionError(errorMessage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be added self.Widget = widget
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is that the user can decide what is in self.Widget
since this is what is access in the get()
method.
Most likely, all the users would do something like this:
def MyClass(QtWidgetMixin):
def __init__(self):
super(MyClass, self).__init__()
self.Wigdet = self.loadUI('/my_path/myWigdet.ui')
myWidget = self.get('WidgetName')
But I could also see something like this:
def MyClass(QtWidgetMixin):
def __init__(self):
super(MyClass, self).__init__()
firstPart = self.loadUI('/my_path/firstPart.ui')
secondPart = self.loadUI('/my_path/secondPart.ui')
self.Wigdet = qt.QWidget()
layout = qt.QVBoxLayout()
layout.addWidget(firstPartWidget)
layout.addWidget(secondPartWidget)
self.Widget.setLayout(layout)
w1 = self.get('WidgetName_FromFirstPart')
w2 = self.get('WidgetName_FromSecondPart')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case, I would recommend to pass the widget as a parameter to get
:
def MyClass(QtWidgetMixin):
def __init__(self):
super(MyClass, self).__init__()
firstPart = self.loadUI('/my_path/firstPart.ui')
secondPart = self.loadUI('/my_path/secondPart.ui')
self.Wigdet = qt.QWidget()
layout = qt.QVBoxLayout()
layout.addWidget(firstPartWidget)
layout.addWidget(secondPartWidget)
self.Widget.setLayout(layout)
w1 = self.get('WidgetName_FromFirstPart', self.Widget)
w2 = self.get('WidgetName_FromSecondPart', self.Widget)
By default, you could also automatically use self.Widget
:
def MyClass(QtWidgetMixin):
def __init__(self):
super(MyClass, self).__init__()
self.loadUI('/my_path/TopLevelWidget.ui')
w = self.get('WidgetName_From_TopLevelWidget')
self.test_get() | ||
|
||
def test_loadUI(self): | ||
mixinWidget = QtMixinTestWidget(auto_setup=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since QtMixinTestWidget
is never instantiated with auto_setup=True
, would it make sense to simplify the code and remove this option ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch :)
For the name, what do you think of |
Also add testing for those methods.
LoadUI() allows to create a widget from a .ui file and findChild() allows quick access to a particular widget by name.
7ffa833
to
0aecec3
Compare
@jcfr: I pushed an updated version if you want to take a look. |
LGTM. Please integrate. 👍 |
@vovythevov The test is failing on the linux factory, do you think you could have a look: http:https://slicer.cdash.org/testDetails.php?test=7737225&build=938646 Thanks |
@jcfr: I cannot reproduce on my UNIX machine and it seems that the isn't failing on UNIX either (although it's still failing on MAC). |
Thanks for looking into this. Let's then wait until we transition to OpenGL2 VTKk backend ... |
This branch aims to add nice-to-have python methods for scripted modules.
Those methods were typically the kind of method I found myself copy/pasting all over my scripted modules and I think they could be beneficial to the community.