Giter Club home page Giter Club logo

pydm's Introduction

Build Status

PyDM: Python Display Manager

PyDM: Python Display Manager

PyDM is a PyQt-based framework for building user interfaces for control systems. The goal is to provide a no-code, drag-and-drop system to make simple screens, as well as a straightforward Python framework to build complex applications.

« Explore PyDM docs and tutorials »

Report bug · Request feature · How to Contribute · Support


Python Qt Wrapper

PyDM project uses the qtpy as the abstraction layer for the Qt Python wrappers (PyQt5/PyQt4/PySide2/PySide). All tests are performed with PyQt5.

Prerequisites

  • Python 3.7+
  • Qt 5.6 or higher
  • qtpy
  • PyQt5 >= 5.7 or any other Qt Python wrapper.

Note: If you'd like to use Qt Designer (drag-and-drop tool to build interfaces) you'll need to make sure you have the PyQt plugin for Designer installed. This usually happens automatically when you install PyQt from source, but if you install it from a package manager, it may be left out.

Python package requirements are listed in the requirements.txt file, which can be used to install all requirements from pip: 'pip install -r requirements.txt'

Running the Tests

In order to run the tests you will need to install some dependencies that are not part of the runtime dependencies of PyDM.

Assuming that you have cloned this repository do:

pip install -r dev-requirements.txt

python run_tests.py

If you want to see the coverage report do:

python run_tests.py --show-cov

Running the Examples

There are various examples of some of the features of the display manager. To launch a particular display run 'python scripts/pydm '.

There is a 'home' display in the examples directory with buttons to launch all the examples:

python scripts/pydm examples/home.ui

Building the Documentation Locally

In order to build the documentation you will need to install some dependencies that are not part of the runtime dependencies of PyDM.

Assuming that you have cloned this repository do:

pip install -r docs-requirements.txt

cd docs
make html

This will generate the HTML documentation for PyDM at the <>/docs/build/html folder. Look for the index.html file and open it with your browser.

Online Documentation

Documentation is available at http://slaclab.github.io/pydm/. Documentation is somewhat sparse right now, unfortunately.

Widget Designer Plugins

pydm widgets are written in Python, and are loaded into Qt Designer via the PyQt Designer Plugin. If you want to use the pydm widgets in Qt Designer, add the pydm directory (which holds designer_plugin.py) to your PYQTDESIGNERPATH environment variable. Eventually, this will happen automatically in some kind of setup script.

Easy Installing PyDM

Using the source code

git clone https://github.com/slaclab/pydm.git
cd pydm
pip install .[all]

Using Anaconda

When using Anaconda to install PyDM at a Linux Environment it will automatically define the PYQTDESIGNERPATH environment variable pointing to /etc/pydm which will have a file named designer_plugin.py which will make all the PyDM widgets available to the Qt Designer. For more information please see our installation guide.

pydm's People

Contributors

anacso17 avatar anleslac avatar colbychang avatar cristinasewell avatar fernandohds564 avatar flowln avatar gabrielfedel avatar herodotus77 avatar hhslepicka avatar hmbui avatar jacquelinegarrahan avatar jbellister-slac avatar justincslac avatar klauer avatar laispc avatar mattgibbs avatar mcb64 avatar ninenein avatar nstelter-slac avatar phys-cgarnier avatar prjemian avatar rcardenes avatar ryan-mcclanahan avatar tacaswell avatar tangkong avatar tcope avatar vespos avatar yektay avatar zdomke avatar zllentz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pydm's Issues

Crash in psp_plugin.py when connecting to an EPICS PV with no precision.

If you are using the pyca EPICS plugin (psp_plugin.py) and you try to connect to a PV that doesn't specify precision, you crash:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/psp/Pv.py", line 218, in __monitor_handler
    cb(e)
  File "/Users/mgibbs/Documents/dev/pydm/pydm/data_plugins/psp_plugin.py", line 181, in monitor_cb
    self.send_new_value(self.pv.value)
  File "/Users/mgibbs/Documents/dev/pydm/pydm/data_plugins/psp_plugin.py", line 230, in send_new_value
    self.prec = self.pv.data['precision']
KeyError: 'precision'

Probably just need to check if the precision key actually exists in self.pv.data.

Request: support for drop-down menus

It could be implemented as part of PyDMRelatedDisplayButton or a new widget altogether.

As in EDM:
image

Macros should be inherited from the parent display, and per-entry you should be able to specify macros that may override the parent ones.

How to install pydm

Hello,

could someone explain me how I could install pydm (Windows 7) the way that I can use its widgets in Qt Designer? I tried copying the pydm folder in the qt5-tools/plugins/ and qt5-tools/plugins/designer folder, with no effect... maybe I am completely wrong with this idea, because there is no .dll file provided in pydm... But it says in the readme that its possible to integrate it to Qt Designer...

Thanks for any Tipps...
piuu

Problem when using the same PV on window and code (with pyepics)

I made a program using pydm, and I put a PV on window, and create the same PV (with pyepics) on the code. When I change pyepics PV, pyepics_plugin (from pydm) receive a callback on send_new_value, but the value is None and it's broke pydm.

I work around this adding a verification if value is None on send_new_value, but I'm not sure if the problem origin is pyepics or pydm.

Create icons for PyDM widgets (used in Qt Designer)

Create unique icons for each PyDM widget, so that they are easier to tell apart at a glance in the Designer widget list. The icons need to be similar enough to the Qt base widgets' icons that they are recognizable to newcomers.

Spin Box Widget

Make a PyDM variant of the QSpinBox widget, with alarm sensitive text and/or borders.

Email group?

Hi there,

Have you considered to create an email group for pydm?
I think questions like doubts and next steps for project could be discussed at that place. We, at LNLS, certainly participate. =)

Bar/Indicator Widget

Add a widget like the EDM Bar and Indicator widgets. This widget is like a single bar in a bar graph - it represents the value from a channel as a bar of varying height. A scale should optionally be displayed next to the bar. Both horizontal and vertical orientations should be supported.

Make PyDM a Python Package

Make so PyDM can be installed.
This is already in progress and almost done...

[x] Use versioner to automatically add the version from GitHub tags and commits to the package.
[ ] Create setup method to remove the usage of python pydm.py my_file.ui when running a standalone project.
[ ] Whatever else is needed and I find while working on this...

[Label] Units

Hi,

  1. Property 'showUnits' seems to be ignored. No matter its value, units are always shown.
  2. If precision is zero and _units_string != "", then only units are shown (value is missing).

I'm attaching a test ui.
Thanks,
Laís

iss_label_showUnit_0.3.0.zip

Embedded Display problem when loading new file

Embedded display is not removing the old widget from the screen.
Fixed at the old version for slaclab/saci to be able to keep the development.
I will also apply this fix to the master in here later.

Attn: @joaopmrod

        @embedded_widget.setter
        def embedded_widget(self, new_widget):
                if new_widget is self._embedded_widget:
                        return
                if self._embedded_widget is not None:
                        self.app.close_widget_connections(self._embedded_widget)
                if self._embedded_widget is not None:
                        self._embedded_widget.setParent(None)
                        self._embedded_widget.destroy()
                self._embedded_widget = new_widget
                self._embedded_widget.setParent(self)
                self.layout.addWidget(self._embedded_widget)
                self.err_label.hide()
                self._embedded_widget.show()
                self.app.establish_widget_connections(self._embedded_widget)
                self._is_connected = True

designer break's with PyDMSlider

When Using
Python3.5
Qt version: 5.6.1
SIP version: 4.18.1
PyQt version: 5.7

Designer break and emit this message:
"TypeError: unable to convert a Python 'NoneType' object to a C++ 'double' instance"

Send Macros to Displays in Python files

This will fix an issue where users need to pass "command_line_args" as the Display offers no way to send in macros from the command line or from widgets.

enum_combo doesn's change PV value

When I use enum_combo, for a ENUM, if a change combo it doesn't change PV.
I tried a fix on add_listener from pyepics_plugin :

 try:                                                                      
   channel.value_signal[str].connect(self.put_value, Qt.QueuedConnection)  
 except:                                                                   
   pass                                                                    
 try:                                                                      
   channel.value_signal[int].connect(self.put_value, Qt.QueuedConnection)  
 except:                                                                   
   pass                                                                    
 try:                                                                      
   channel.value_signal[float].connect(self.put_value, Qt.QueuedConnection)
 except:                                                                   
   pass                                                                    

This fix the the problem, but the combo always go back to first item (it set correctly the PV, but doesn't show value correct).

Symbol Widget

Make a widget like the EDM Symbol Widget. This widget takes an Enum channel as input, and displays a different image file based on the value of the enum.

How to create a window without the PyDMApplication bar?

Hi,
is it possible to use pydm without the standard top bar? I didn't found an easy way to get rid of it... for some it may be usefull but especially on my system (Windows) all button clicks result in a python crash.
Thanks!
piuu

Widgets categories

Hi,
The list of widgets is getting large and Designer loads them in random order. Sometimes it is difficult to quickly find one of them. So it would be interesting to create subcategories. E.g.: monitors, controls, plot, drawing etc.
Icons (#44) will make it easier to find a widget, but categories would make it even more organized.

Maybe the group name of a widget can be passed as argument in qtplugin_factory?
Thanks,
Laís

Error when starting python pydm.py pythonui.py on Windows(?)

Hi all,
i tried to run a converted .py file with pydm and it got some error in the load_py_file-function in pydm/application.py:

Traceback (most recent call last):
  File "pydm.py", line 20, in <module>
    app = PyDMApplication(ui_file=pydm_args.displayfile, command_line_args=pydm_args.display_args, perfmon=pydm_args.perfmon, macros=macros)
  File "E:\pydm\pydm\application.py", line 67, in __init__
    self.make_window(ui_file, macros, command_line_args)
  File "E:\pydm\pydm\application.py", line 129, in make_window
    main_window.open_file(ui_file, macros, command_line_args)
  File "E:\pydm\pydm\main_window.py", line 66, in open_file
    self.open_abs_file(filename, macros, command_line_args)
  File "E:\pydm\pydm\main_window.py", line 69, in open_abs_file
    widget = self.app.open_file(filename, macros, command_line_args)
  File "E:\pydm\pydm\application.py", line 167, in open_file
    widget = self.load_py_file(filepath, args)
  File "E:\pydm\pydm\application.py", line 154, in load_py_file
    return module.intelclass(args=args)
AttributeError: module 'intelclass' has no attribute 'intelclass'

Somehow the module module is already the intelclass?
Thanks for you help,
menno

Example home.ui and other crash because of incorrect file path string appending

Hello,
I just started with pydm and want to try out a few of the shipped examples. Problem is: when I start python.exe pydm.py examples/home.ui the home-ui will open but every button click will result in a python crash with the following error:

Traceback (most recent call last):
  File "E:\pydm_testing\pydm\widgets\related_display_button.py", line 54, in mouseReleaseEvent
    self.open_display()
  File **"E:\pydm_testing\pydm\widgets\related_display_button.py",** line 65, in open_display
    self.window().go(self.displayFilename, macros=macros)
  File "E:\pydm_testing\pydm\main_window.py", line 96, in go
    self.open_file(ui_file, macros, command_line_args)
  File "E:\pydm_testing\pydm\main_window.py", line 66, in open_file
    self.open_abs_file(filename, macros, command_line_args)
  File "E:\pydm_testing\pydm\main_window.py", line 69, in open_abs_file
    widget = self.app.open_file(filename, macros, command_line_args)
  File "E:\pydm_testing\pydm\application.py", line 164, in open_file
    widget = self.load_ui_file(filepath, macros)
  File "E:\pydm_testing\pydm\application.py", line 144, in load_ui_file
    return uic.loadUi(f)
  File "C:\Program Files\Python35\lib\site-packages\PyQt5\uic\__init__.py", line 226, in loadUi
    return DynamicUILoader(package).loadUi(uifile, baseinstance, resource_suffix)
  File "C:\Program Files\Python35\lib\site-packages\PyQt5\uic\Loader\loader.py", line 72, in loadUi
    return self.parse(filename, resource_suffix, basedir)
  File "C:\Program Files\Python35\lib\site-packages\PyQt5\uic\uiparser.py", line 1003, in parse
    document = parse(filename)
  File "C:\Program Files\Python35\lib\xml\etree\ElementTree.py", line 1195, in parse
    tree.parse(source, parser)
  File "C:\Program Files\Python35\lib\xml\etree\ElementTree.py", line 585, in parse
    source = open(source, "rb")
FileNotFoundError: [Errno 2] No such file or directory: 'examplesimage_view/many_images.ui'

The last line shows the error: there is no slash after examples/ -> file not found...
I tried to alter the home.ui by adding a slash in front of image_view but then its leaving the "example" and its also not working...

Did I do something wrong? Is it a bug? Did I miss something while installing all the requiered packages? I tried it with python 3.5 and 3.6...

Thanks in advance,
piuu

Drawing Tool Widgets

EDM and CSS have widgets that just show static drawn shapes (circles, rectangles, arcs, triangles, etc.) It would be nice if PyDM had similar tools.

Support for manual range on plots

Currently I only see in the properties the option to enable/disable the autoRange[X/Y]. I would be nice, if when disabled, the user could select a range manually.

I'm using PyDMWaveformPlot for this example.

Read-only mode

Add a menu option to enable/disable "read-only mode", which prevents PyDM from writing to any channel.

Add a 'default protocol' environment variable.

Add an environment variable where you can specify a protocol to use by default if one is not provided for a channel (i.e. if you set the default protocol to 'ca', and specify a channel with just 'MTEST:Float', PyDM will interpret it as 'ca://MTEST:Float').

Byte Widget

Add a widget that takes an int channel as input, and shows an on/off indicator for each bit in the binary value of the input. Each bit should have a corresponding label that the user can configure.

Is it possible to open a PyDM Dialog-Window from a PyDM Window?

Hi,
I tried to create a pydm window with some labels to show the current status of some devices (main_window) and also allows to change all kind of settings for each device by clicking a "device-settings" button and open a complete new pydm window (dialog). What happens now is that the .ui of the dialog just opens as an overlay in the main_window.

I created a minimal example using testing-ioc.py PVs:

testgui.py

from pydm.PyQt import uic
from pydm.PyQt.QtCore import QObject, pyqtSlot, pyqtSignal
from pydm.PyQt.QtGui import QWidget
from os import path
from pydm import Display

class MainWindowApp(Display):
    def __init__(self, parent=None, args=None):
        super(MainWindowApp, self).__init__(parent=parent, args=args)
        self.ui.btn_settings.clicked.connect(lambda: self.handlesubwindow('settings'))

    @property
    def display_manager_window(self):
        return self.window()

    def ui_filename(self):
        return 'main_window.ui'

    def ui_filepath(self):
        pp = path.join(path.dirname(path.realpath(__file__)), self.ui_filename())
        print("Path", pp)
        return pp

    @pyqtSlot()
    def handlesubwindow(self, name):
        if name == 'settings':
            dialog = SettingsUI(self)
            try:
                dialog.show()
            except:
                raise


class SettingsUI(Display):
    def __init__(self, parent=None, args=None):
        super(SettingsUI, self).__init__(parent=parent, args=args)

    @property
    def display_manager_window(self):
        return self.window()

    def ui_filename(self):
        return 'dialog.ui'

    def ui_filepath(self):
        pp = path.join(path.dirname(path.realpath(__file__)), self.ui_filename())
        print("Path", pp)
        return pp

main_window.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>399</width>
    <height>69</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="0" column="1">
    <widget class="PyDMLabel" name="PyDMLabel">
     <property name="toolTip">
      <string/>
     </property>
     <property name="whatsThis">
      <string/>
     </property>
     <property name="channel">
      <string>ca://MTEST:VoltOffset</string>
     </property>
    </widget>
   </item>
   <item row="2" column="0" colspan="2">
    <widget class="QPushButton" name="btn_settings">
     <property name="text">
      <string>Open Settings</string>
     </property>
    </widget>
   </item>
   <item row="0" column="0">
    <widget class="QLabel" name="label">
     <property name="text">
      <string>MTEST:VoltOffset</string>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <customwidgets>
  <customwidget>
   <class>PyDMLabel</class>
   <extends>QLabel</extends>
   <header>pydm.widgets.label</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

dialog.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>385</width>
    <height>135</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="1" column="1">
    <widget class="PyDMSpinbox" name="PyDMSpinbox">
     <property name="toolTip">
      <string/>
     </property>
     <property name="whatsThis">
      <string/>
     </property>
     <property name="channel">
      <string>ca://MTEST:VoltOffset</string>
     </property>
    </widget>
   </item>
   <item row="1" column="0">
    <widget class="QLabel" name="label_2">
     <property name="text">
      <string>MTEST:VoltOffset (SpinBox)</string>
     </property>
    </widget>
   </item>
   <item row="3" column="0">
    <widget class="QLabel" name="label_4">
     <property name="text">
      <string>MTEST:MinValue (SpinBox)</string>
     </property>
    </widget>
   </item>
   <item row="0" column="1">
    <widget class="PyDMLabel" name="PyDMLabel">
     <property name="toolTip">
      <string/>
     </property>
     <property name="whatsThis">
      <string/>
     </property>
     <property name="channel">
      <string>ca://MTEST:VoltOffset</string>
     </property>
    </widget>
   </item>
   <item row="2" column="0">
    <widget class="QLabel" name="label_3">
     <property name="text">
      <string>MTEST:TriggerDelay (SpinBox)</string>
     </property>
    </widget>
   </item>
   <item row="0" column="0">
    <widget class="QLabel" name="label">
     <property name="text">
      <string>MTEST:VoltOffset (Label)</string>
     </property>
    </widget>
   </item>
   <item row="4" column="0">
    <widget class="QLabel" name="label_5">
     <property name="text">
      <string>MTEST:MaxValue (SpinBox)</string>
     </property>
    </widget>
   </item>
   <item row="2" column="1">
    <widget class="PyDMSpinbox" name="PyDMSpinbox_2">
     <property name="toolTip">
      <string/>
     </property>
     <property name="whatsThis">
      <string/>
     </property>
     <property name="channel">
      <string>ca://MTEST:TriggerDelay</string>
     </property>
    </widget>
   </item>
   <item row="3" column="1">
    <widget class="PyDMSpinbox" name="PyDMSpinbox_3">
     <property name="toolTip">
      <string/>
     </property>
     <property name="whatsThis">
      <string/>
     </property>
     <property name="channel">
      <string>ca://MTEST:MinValue</string>
     </property>
    </widget>
   </item>
   <item row="4" column="1">
    <widget class="PyDMSpinbox" name="PyDMSpinbox_4">
     <property name="toolTip">
      <string/>
     </property>
     <property name="whatsThis">
      <string/>
     </property>
     <property name="channel">
      <string>ca://MTEST:MaxValue</string>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <customwidgets>
  <customwidget>
   <class>PyDMLabel</class>
   <extends>QLabel</extends>
   <header>pydm.widgets.label</header>
  </customwidget>
  <customwidget>
   <class>PyDMSpinbox</class>
   <extends>QDoubleSpinBox</extends>
   <header>pydm.widgets.spinbox</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

So the questions are: Is it possible to get this work and how do you do this in PyDM?

Thanks for your help!
menno

Getting Started Guide

PyDM needs better documentation for newcomers - how to install it, how to get the widgets working in designer, how to write a script-based display, etc.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.