Skip to content
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

Closed
wants to merge 2 commits into from
Closed

Conversation

vovythevov
Copy link

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.

@vovythevov
Copy link
Author

@jcfr: Would you mind reviewing ?

Copy link
Member

@jcfr jcfr left a 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,
Copy link
Member

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
Copy link
Member

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,
Copy link
Member

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)
Copy link
Member

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):
Copy link
Member

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"
Copy link
Member

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):
Copy link
Member

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
Copy link
Member

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
Copy link
Member

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.

Copy link
Author

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)
Copy link
Member

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 ?

Copy link
Author

@vovythevov vovythevov Nov 18, 2016

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')

Copy link
Member

@jcfr jcfr Nov 18, 2016

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)
Copy link
Member

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 ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch :)

@jcfr
Copy link
Member

jcfr commented Nov 18, 2016

For the name, what do you think of QtUILoaderMixin ? Or something similar

LoadUI() allows to create a widget from a .ui file and findChild() allows
quick access to a particular widget by name.
@vovythevov
Copy link
Author

@jcfr: I pushed an updated version if you want to take a look.

@jcfr
Copy link
Member

jcfr commented Dec 8, 2016

LGTM. Please integrate. 👍

@vovythevov
Copy link
Author

Integrated in r25595 and r25596

@vovythevov vovythevov closed this Dec 8, 2016
@vovythevov vovythevov deleted the PythonScriptedInterface branch December 8, 2016 21:11
@jcfr
Copy link
Member

jcfr commented Dec 9, 2016

@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

@vovythevov
Copy link
Author

@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).

@jcfr
Copy link
Member

jcfr commented Dec 16, 2016

Thanks for looking into this. Let's then wait until we transition to OpenGL2 VTKk backend ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
2 participants