geoptics.guis.qt package¶
Package contents¶
Qt backend.
Interface with IPython¶
And at the ipython3 prompt, %gui qt5 has to be issued,
otherwise the command line is stuck until the window is closed.
So, starting from a shell:
ipython3
And from the ipython command line:
%load_ext autoreload
%autoreload 2 # for debugging purposes, reload modules if changed
%gui qt5 # mandatory, before %run, otherwise blocked
%run t_geo # runs the t_geo.py script
sip API¶
In python3, sip.setapi('QVariant', 2) is default, so that
any Qt method that returns a QVariant will return a python type
instead.
This means that no new_pos = value.ToPoint() are needed anymore.
Just use new_pos = value directly.
Do not use QString, this is deprecated.
we use sip.setapi('QString', 2)
cf. http://stackoverflow.com/a/22184911/3565696
Beware that with sip.setapi('QVariant', 2),
there is a caveat when using QSettings.
in a nutshell, we must use the type= keyword argument
for value()
Architecture¶
elements/gui relationships¶
When working with a guis.qt.scene.Scene, either on the command line or from the gui, only the gui class qt.regions.Polycurve instance exist. There is no pure elements.regions.Polycurve instance at all.
The gui class qt.regions.Polycurve inherits from elements.regions.Polycurve. Methods that could lead to round trips are overloaded, and just call a method of qt.regions._GPolycurve with the same name, prefixed with g_. At this point, everything looks like a direct modification to the Qt part only.
All qt.regions._GPolycurve methods act on the Qt items, eventually triggering a call to the corresponding elements.regions.Polycurve method, never to qt.regions.Polycurve methods.
Here is an example of such a call: elements.regions.Polycurve.translate(self.e, …). In this call, self is the _GPolycurve, self.e is a property yielding the corresponding qt.regions.Polycurve instance.
Advantages of such a layout are
Imperative style programming. Commands are excuted immediately, and only once.
There are no round trips (element => gui => element => …)
It is possible to exploit fully the QGraphicsView framework for items selection and movement. It is is actually what settled this choice in the beginning.
Changing to a model-observer pattern or model-view-controller would involve a rewrite of the items displacement. For instance the gui would take only the mouse movements, and transmit them to the controller.
Some disadvantages of the current layout are
need for Scene.class_map (explained later). But maybe this could fit well with plugins.
foreseen issues for multithreaded operations. But the display is currently quite fast, with room for optimisations; multithreads are perhaps not worth the trouble.
Whether advantages dominate is not clear at the moment, but here it is. Forks are welcome.
Submodules¶
geoptics.guis.qt.counterpart module¶
Graphical counterpart to elements.
See also
The purpose is described in the Architecture section.
- class geoptics.guis.qt.counterpart.GOverload(*names)[source]¶
Bases:
objectDecorator factory.
Used to make the interface class
cls(which inherits from element) call_G<cls>methods instead.- Parameters:
*names – names (str) of methods to be overloaded
- Returns:
decorator, which effectively replaces each call to
<cls>.<name>(self, ...)with_G<cls>.g_<name>(self.g, ...)
Note
_G<cls>must be in the same module as<cls>Example
# in guis.qt.regions class _GPolycurve(...): ... def g_translate(...): ... @GOverload("start", "add_line", "add_arc", "close", "translate") class Polycurve(elements.regions.Polycurve): ... # in ipython, create a region with qt gui interface r = guis.gt.sources.Polycurve(...) # the following will call # guis.gt.sources._GPolycurve.g_translate(r.g, ...) # instead of the normaly inherited # elements.regions.Polycurve.translate(self, ...) r.translate(...)
- geoptics.guis.qt.counterpart.g_counterpart(original_class)[source]¶
Enhance a graphical class to be a counterpart to an element.
Add
elementto the __init__ keyword arguments. Add the.eproperty to access the element.Note
This function is intended to be used as a decorator. Decorators should be commutative. Hence element is a keyword - not positional - argument.
geoptics.guis.qt.handles module¶
Handles to control elements in the guis.qt backend.
Currently handles are always naturally related to another Qt item.
This item should be the handle parent.
Allowing handles without any parent (parent=None) is not implemented yet.
Note
PointHandle derive from a Qt class,
and are living in the Qt realm only.
They are not aware of the underlying elements.
Hence the Qt self.scene() should be used,
instead of self.scene – mind the ().
This simplifies the calls, when PointHandle are created with given
parent=. The Qt scene() is inherited from parent,
hence no need to add the scene= keyword.
This is not the case for LineHandle that are python objects
- class geoptics.guis.qt.handles.LineHandle(line, parent=None, zvalue=1000, **kwargs)[source]¶
Bases:
objectHandle to control a “line”.
That is, control a point and a vector from that point.
- Parameters:
line (Line) –
parent (QGraphicsItem) – the parent for all items composing this handle
- property h_p0¶
Handle for the starting point of the line.
- property h_u¶
Handle for the end of the u vector.
- property line_item¶
Line item, joining the point and the end of the u vector.
- reset_move()[source]¶
Store the initial position, for move restrictions.
- setZValue(zvalue)[source]¶
Set the z_value.
The zvalue can be that of the item to be controlled. The Qt items composing the LineHandle will be set to z_values 1 or 2 above, to ensure their visibility.
- class geoptics.guis.qt.handles.PointHandle(*args: Any, **kwargs: Any)[source]¶
Bases:
QGraphicsEllipseItemHandle to control a “point”.
- Parameters:
relative (bool) –
False (default): positions are absolute and in scene coordinates
True: positions are relative to the parent, and in view coordinates
Note
Beware that a call to
setPos()will emit signal_moved. Hence, callsetPos()first, and only then connect to signal_moved.- ignore_move_restrictions¶
ignore move restrictions ? Initially True so that the first move, to the initial position, is free The user is responsible for setting it back to False, to honor the scene setting
- reset_move()[source]¶
Store the initial position, for move restrictions.
- signal_moved¶
Signal to be emitted when the PointHandle is moved.
slot args: (dx, dy), where dx and dy are displacements along x and y, in scene coordinates.
- signal_selected_change¶
Signal emitted when an ItemSelectedChange occurs.
slot args: (
boolean)
geoptics.guis.qt.main module¶
geoptics.guis.qt.rays module¶
Rays for the guis.qt backend.
- class geoptics.guis.qt.rays.Ray(line0=None, s0=100, source=None, n=None, tag=None, zvalue=100, **kwargs)[source]¶
Bases:
RayRay of light.
This is the Ray that should be instanciated, in the
guis.qtbackend.Note
Regular users should not use Ray directly, but instead use one of the sources in
qt.sources.- add_part(*args, g_func=<function _GRay.g_add_part>, **kwargs)¶
Same as
geoptics.elements.rays.Ray.add_partOverloaded to call
_GRay.g_add_part(self.g, ...)
- change_s(*args, g_func=<function _GRay.g_change_s>, **kwargs)¶
Same as
geoptics.elements.rays.Ray.change_sOverloaded to call
_GRay.g_change_s(self.g, ...)
- draw(*args, g_func=<function _GRay.g_draw>, **kwargs)¶
Same as
geoptics.elements.rays.Ray.drawOverloaded to call
_GRay.g_draw(self.g, ...)
- property g¶
Return the corresponding graphical item.
geoptics.guis.qt.regions module¶
Regions for the guis.qt backend.
- class geoptics.guis.qt.regions.Polycurve(n=None, scene=None, tag=None, zvalue=0, **kwargs)[source]¶
Bases:
PolycurveDefine a region inside curves (for instance line segments).
- Parameters:
scene (Scene) – to belong to.
- add_arc(*args, g_func=<function _GPolycurve.g_add_arc>, **kwargs)¶
Same as
geoptics.elements.regions.Polycurve.add_arcOverloaded to call
_GPolycurve.g_add_arc(self.g, ...)
- add_line(*args, g_func=<function _GPolycurve.g_add_line>, **kwargs)¶
Same as
geoptics.elements.regions.Polycurve.add_lineOverloaded to call
_GPolycurve.g_add_line(self.g, ...)
- close(*args, g_func=<function _GPolycurve.g_close>, **kwargs)¶
Same as
geoptics.elements.regions.Polycurve.closeOverloaded to call
_GPolycurve.g_close(self.g, ...)
- start(*args, g_func=<function _GPolycurve.g_start>, **kwargs)¶
Same as
geoptics.elements.regions.Polycurve.startOverloaded to call
_GPolycurve.g_start(self.g, ...)
- translate(*args, g_func=<function _GPolycurve.g_translate>, **kwargs)¶
Same as
geoptics.elements.regions.Polycurve.translateOverloaded to call
_GPolycurve.g_translate(self.g, ...)
- class geoptics.guis.qt.regions._GPolycurve(**kwargs)[source]¶
Bases:
QGraphicsPathItemGraphical class corresponding to
Polycurve.Note
_G* objects are living in the Qt realm only.
They are not aware of the underlying elements. Hence the Qt
self.scene()should be used, instead ofself.scene()– mind the().Note
when about to change the pos() of this item, e.g. before a
setPos()of atranslate(), first issue areset_move()- property e¶
The corresponding element.
geoptics.guis.qt.scene module¶
Scene to be used with the Qt gui.
- class geoptics.guis.qt.scene.Scene(**kwargs)[source]¶
Bases:
SceneThe Scene that should be instanciated by user, in the guis.qt backend.
- add(other, tag=None)[source]¶
Add an element to the scene.
- Parameters:
other (dict or element) – the element to be added, either as a config dictionnary, or directly as an object such as
guis.qt.sources.Beamorguis.qt.regions.Polycurve
- class_map¶
correspondance between names in config data, and classes
- class geoptics.guis.qt.scene._GScene(**kwargs)[source]¶
Bases:
QGraphicsSceneThe graphical class corresponding to
Scene.- Parameters:
element (
Scene) – The corresponding element
See also
More informations on the relationships between Scene and _GScene can be found in the Architecture section.
- property active_view¶
Get current active view.
- property e¶
The corresponding element.
- keyPressEvent(event)[source]¶
Handle key pressed events.
Delete: remove selected itemsESC: deselect all
- move_restrictions_on¶
Whether objects moves should be restricted.
- move restrictions¶
Some displacements can be restricted to certain directions. If
move_restrictions_onis True, then the displacements are constrained to be along the x or y direction. The actual direction (x or y) should be the closest to the mouse displacement. For instance, if the mouse movement is mainly horizontal, then aPointHandlewould move along x only.This requires to store the initial position, at the beginning of the displacement. This is done by
reset_move()slots.
- signal_element_moved¶
- signal_mouse_position_changed¶
- signal_remove_selected_items¶
- signal_reset_move¶
- signal_set_all_selected¶
geoptics.guis.qt.signal module¶
Signal for non-QObjects.
- class geoptics.guis.qt.signal.Signal[source]¶
Bases:
objectOnly QObject can send signals.
We need this trick for GraphicsItems taken from http://stackoverflow.com/questions/21101500/custom-pyqtsignal-implementation
see also http://abstractfactory.io/blog/dynamic-signals-in-pyqt/
a priori the only problem is that it can’t be used across threads
Note
Contrary to pyqtSignal, a new Signal instance must be created for each object instance, otherwise signals would be mixed up between instances.
Hence the correct place is in the
__init__function:def __init__(self): self.signal_name = Signal()
geoptics.guis.qt.sources module¶
Sources of light rays for the guis.qt backend.
- class geoptics.guis.qt.sources.Beam(line_start=None, s_start=None, line_end=None, s_end=None, N_inter=0, scene=None, tag=None, zvalue=100, **kwargs)[source]¶
Bases:
BeamBeam source.
This is the Beam that should be instanciated by user, in the
guis.qtbackend.
- class geoptics.guis.qt.sources.SingleRay(line0=None, s0=None, scene=None, tag=None, zvalue=100, **kwargs)[source]¶
Bases:
SingleRaySingle ray source.
This is the SingleRay that should be instanciated by user, in the
guis.qtbackend.
- class geoptics.guis.qt.sources._GBeam(element=None, zvalue=100, **kwargs)[source]¶
Bases:
_GSourceThe graphical class corresponding to
Beam.- Parameters:
(class (element) – .Beam): the corresponding element.
- class geoptics.guis.qt.sources._GSingleRay(element=None, zvalue=100, **kwargs)[source]¶
Bases:
_GSourceThe graphical class corresponding to
SingleRay.- Parameters:
element (
SingleRay) – the corresponding element.
- class geoptics.guis.qt.sources._GSource(zvalue=100, **kwargs)[source]¶
Bases:
QGraphicsItemThe corresponding graphical class to sources.
- Parameters:
element (Source) – a source element belonging to
guis.qt.sources, such asguis.qt.sources.Beam.
- property e¶
The corresponding element.
geoptics.guis.qt.view module¶
View displaying the scene.
- class geoptics.guis.qt.view.GraphicsView(**kwargs)[source]¶
Bases:
QGraphicsViewScene holder.