- Timestamp:
- Aug 5, 2015, 5:32:09 PM (9 years ago)
- Branches:
- Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
- Children:
- 3d5b5b
- Parents:
- fcdf05
- git-author:
- Frederik Heber <heber@…> (07/15/15 13:56:58)
- git-committer:
- Frederik Heber <heber@…> (08/05/15 17:32:09)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/documentation/constructs/qt-gui.dox
rfcdf05 r52c5d4 20 20 * In the following we want to explain some of the details that are involved. 21 21 * 22 * \section qt-gui-general General Concepts 23 * 24 * Let us first discuss about the general concepts. 25 * 26 * MoleCuilder is about atoms, bonds and the molecules made up by them. But 27 * there is more: There are fragments, potentials, shapes, and so on. 28 * 29 * In the Qt GUI all of these are displayed in certain areas of the screen 30 * and also in a certain manner: 31 * -# the 3D view represents a three-dimensional representation of all atoms, 32 * and their bonds or possibly the molecules they form alone. Also the 33 * bounding box is shown and all selected shapes. Atoms or molecules can 34 * be selected by clicking. The view can be manipulated through rotation 35 * and translation. 36 * -# an element list shows all available elements of the period table. 37 * -# a molecule list shows all present molecules sorted by their formula. 38 * -# a fragment list shows all fragments with their energies and contributions 39 * -# a potential list shows all currently instantiated potentials and 40 * gives a 2D plot. 41 * -# a shape list displays all currently available shapes, allows to select 42 * them and buttons allow to combine them via boolean operation. 43 * -# an info box informs about the current atom/molecule the mouse pointer 44 * is hovering over. 45 * 46 * So, there are many objects that need to be filled with information and 47 * they need to access the World and other singletons in order to obtain 48 * this information. 49 * 50 * One major obstacle, or rather THE major obstacle, is that Qt is threaded, 51 * i.e. the Actions are processed in one thread and the Gui does its event 52 * processing in another one. Qt's Signal/Slot system is handled via this 53 * event system, i.e. a signal launched by one thread may be handled by 54 * the slot function in another thread. The Observer/Observable system 55 * of the CodePatterns which we used internally/outside Qt's scope does 56 * not do this. 57 * 58 * Also, signals may get delayed. This can happen either deliberately, e.g. 59 * there is a QTimer that only updates an object in regular intervals, or 60 * because of asynchronous threads. Elsewhen, the slot callback for a 61 * certain signal is called directly. For all of these cases we have to 62 * accommodate. This is especially problematic with the instantiation and 63 * destruction of objects. 64 * 65 * A clarifying example: Imagine an atom is constructed, the AtomObserver 66 * notifies about it, but the information is not processed immediately. 67 * Shortly after, the atom is destroyed again before its representation is 68 * instantiated in the GUI. Afterwards the GUI attempts to instantiate it 69 * but can not longer access the atom for its position and element. 70 * 71 * The only possible way out is to duplicate information. This is the usual 72 * way how to deal with environments with multiple threads. I.e. all the 73 * information that the GUI representants of information inside the World 74 * needs to be doubled such that when the original information is destroyed 75 * the representant can still be accessed as long as needed. 76 * 77 * \subsection qt-gui-general-observedvalue Observed Value 78 * 79 * These representants are called \a ObservedValue in CodePatterns and they 80 * are used everywhere in the Qt Gui. 81 * 82 * They contain an internal information, e.g. a boolean, a Vector or even 83 * a complex structure such as a Tesselation. They require an updater 84 * function to obtain the derived information from the original source. And 85 * they signOn to the source in order to be notified either generally on 86 * updates or for specific channels only. 87 * 88 * The ObservedValue will automatically and immediately update its internal 89 * representation of the derived information by calling the updater function 90 * as soon as it has been informed about the update. Hence, the internal 91 * information is always up-to-date and lives beyond the scope of the 92 * source of the information until its own destruction. As updates are 93 * processed immediately, this pattern only makes sense for "small" pieces 94 * of information, i.e. when the updater function is very light-weight and 95 * does not do much in terms of using computing resources. 96 * 97 * Note that there is another concept that is opposite to the observed value, 98 * namely the Cacheable. This pattern will update itself only when requested, 99 * referred to as "lazy evaluation". Hence, this pattern is used for "large" 100 * pieces of information that require more computing resources within the 101 * updater. Also, the Cacheable's information can only be obtained as long 102 * as the source of information is still alive. 103 * 104 * Both concepts can be used in threaded environments as mutexed are used to 105 * protect read and write accesses. 106 * 107 * \subsection qt-gui-general-signalslot Observer/Observable and Signal/Slot 108 * 109 * In the following we refer to Observer/Observable as "O/O" and to Signal/Slot 110 * as "S/S". 111 * 112 * One thing we need to do is to translate between update() or 113 * recieveNotification() calls from an Observable and subsequent signal/slot 114 * calls. The general idea is to use these ObservedValues as translation 115 * points for small pieces of information and Cacheables for larger pieces. 116 * 117 * However, we need more of these translation points: 118 * -# GLWorldView checks for 119 * -# World's MoleculeInserted 120 * -# World's SelectionChanged 121 * -# WorldTime's TimeChanged 122 * -# each molecule's AtomInserted and AtomRemoved 123 * -# AtomObservable's AtomChanged. 124 * -# ShapeRegistry's ShapedAdded, ShapeRemoved, and SelectionChanged 125 * -# GLMoleculeObject_molecule checks for 126 * -# molecule's AtomInserted, AtomRemoved, AtomMoved, IndexChanged 127 * -# World's SelectionChanged 128 * 22 129 * \section qt-gui-qt3d Qt3D and the way to get atoms and bonds displayed 23 130 * 24 * Atoms and Bonds have to displayed, the widget for this is GLWorldView. To 25 * this class belongs GLWorldScene that contains lots of GLMoleculeObject's or 26 * nodes in the speak of Qt3D. We have four derived class for these kind of 27 * objects: 28 * -# GLMoleculeObject_atom: for each atom, 29 * -# GLMoleculeObject_bond: for each "side" of the bond (each represents half of 30 * the bond that join in the middle between the two atoms), 31 * -# GLMoleculeObject_molecule: for each molecule (shows a box is selected), 32 * -# GLMoleculeObject_shape: shows the shapes in the ShapeRegistry. 33 * 34 * We can only add new nodes to the Qt3D scene at the level of GLWorldScene, 35 * hence all insertion go through this instance to add new nodes. Destruction 36 * may occur anywhere as the new nodes are parentized to the scene. 37 * 38 * \subsection qt-gui-qt3d-atoms How atom object are constructed/destroyed. 39 * 40 * Atoms are rendered as spheres, see createAtom(). GLWorldView gets notified 41 * by the World about new and removed atoms via the Channel's World::AtomInserted 42 * and World::AtomRemoved. It translates these into Qt signals with the correct 43 * affected atom, by looking at 44 * \code 45 * const atom *_atom = World::getInstance().lastChanged<atom>(); 46 * \endcode 47 * These signals call slots of GLWorldScene that has a map of all contained 48 * GLMoleculeObject, one for either of the two kinds: 49 * -# GLWorldScene::atomInserted(): create a new node and connect its signals 50 * with us, add to map 51 * -# GLWorldScene::atomRemoved(): disconnect, remove from map, destroy 52 * 53 * We do not need to destroy the node itself as it is connected via the Observer 54 * mechanism to the associated atom 55 * 56 * \subsection qt-gui-qt3d-bonds How bond object are constructed/destroyed. 57 * 58 * Bonds are displayed as cylinders that elongate from one atom to the midpoint 59 * of the bond (i.e. the spot in between the two atoms). That is we have always 60 * two cylinders per bond. That's why we need to distinguish 61 * GLMoleculeObject_bond::SideOfBond to get the right node. 62 * 63 * Bonds are not as easy as atoms: The World does not know about bonds being 64 * created or destroyed, only the atoms themselves know about them. 65 * 66 * That's way the atom node object GLMoleculeObject_atom is an Observer of is 67 * associated atom and listens to the Channel AtomObservable::BondsAdded. It then 68 * translates this into a Qt signal that calls a slot GLWorldScene:BondInserted. 69 * 70 * 71 * Bonds themselves are also Observables, as are atoms. Hence, 72 * GLMoleculeObject_bond connect via the Observer mechanism to their associated 73 * bond and are thus notified when they are destroyed. 74 * 75 * Additionally, we use GLWorldScene to do some bookkeeping about all bond nodes. 76 * This is not strictly required but might in general be useful. Hence, signals 77 * notify GLWorldScene also about GLWorldScene::bondRemoved that are emitted by 78 * the node itself. 131 * By far the most difficult component of the Qt GUI is the 3D view. So, 132 * let us explain it in detail. 133 * 134 * The general widget making up the view is called \a GLWorldView. It contains 135 * the GLWorldScene (i.e. all atoms, bonds, molecules, and shapes). Also 136 * the "dreibein" and the domain. It processes key presses and mouse events 137 * to manipulate the view. And it also serves as the translator O/O to S/S 138 * system. 139 * 140 * The GLWorldScene contains the actual nodes of the molecular system, i.e. 141 * the atoms, bonds, molecules, and shapes. All of these are derived from 142 * GLMoleculeObject and have their parent to the instance of the GLWorldScene 143 * which goes through its list of children and to call draw() on them. 144 * 145 * The bottom-most structure is GLMoleculeObject_atom displaying a sphere 146 * of an element-specific color at the atom's position. The atom relies 147 * on its representants to be contain all required information but it 148 * is also signOn() to the atom itself whose O/O are translated to S/S 149 * for processing whenever desired. 150 * 151 * Next comes the GLMoleculeObject_bond which displays a cylinder between 152 * two atoms. Actual, a true bond consists of two of these objects. If the 153 * bond is between heterogeneous atoms each half will be displayed in the 154 * color of the closer atom. These bond objects are not associated with 155 * the atoms directly as the are linked to two atoms at the same time. They 156 * rely on ObservedValues for position and element of either atom and for 157 * the degree of the bond itself. 158 * 159 * Parallel to these are GLMoleculeObject_shape which display the surface 160 * of a selected shape. A shape in general does not change after instantation, 161 * hence the shape lives with the information it gets on instantiation till 162 * it dies. 163 * 164 * Finally, the GLMoleculeObject_molecule owns both atoms and bonds. This 165 * allows for switching the view between the classical ball-and-stick model 166 * and the tesselated surface of the molecule. The latter uses a lot less 167 * triangles and thus is faster. Also, it is especially suited for large 168 * molecules. The molecule also needs ObservedValues for its bounding box 169 * (used to show when it's selected), the index, the selection status, 170 * and the list of atom ids. As Cacheable we use the tesselation structure. 171 * 172 * \section qt-gui-cases Sample cases 173 * 174 * Let us discuss some cases and how the different instances interact. 175 * 176 * \section qt-gui-cases-start Start 177 * 178 * When molecuilder is started, several singletons such as the World and 179 * others are instantiated. No atoms are yet present, no bonds, no molecules. 180 * Hence, nothing to display yet. 181 * 182 * Before launching any Action the ActionQueue is forced to wait till the 183 * GUI is finished instantiating. This is to ensure that GLWorldView and 184 * others are in place to receive signals from the O/O system. 185 * 186 * When a molecule is loaded, the instantiation of a GLMoleculeObject_molecule 187 * does not happen immediately. Hence, GLWorldView listens to the World's 188 * MoleculeInserted. On receiving it, it also signOn()s to the molecule 189 * to get its subjectKilled(). It translates then these and also all 190 * AtomInserted and AtomRemoved to the S/S system as moleculeInserted, 191 * moleculeRemoved and atomInserted/atomRemoved respectively, which are 192 * processed by the GLWorldScene. 193 * 194 * The GLWorldScene records any atomInserted/atomRemoved until the molecule 195 * has been instantiated. On instantiation all recorded events are played. 196 * This is to ensure that there is no overlap in instantiation and signOn() 197 * to the molecule. If we would simply get all atoms which are present 198 * on processing the molecule's instantiation we might stumble over a signal 199 * of a molecule of a just added atom. This occurs frequently as both 200 * are very much correlated. 201 * 202 * GLWorldView keep track of all ObservedMolecules. And GLWorldScene keeps 203 * track of all shapes and molecules in the scene. Each 204 * GLMoleculeObject_molecule in turn keeps track of all atoms and bonds in 205 * its part of the scene. 79 206 * 80 207 * \section QtElementList 81 208 * 82 * Lists for each element how often it occur es in the world. Selecting an entry209 * Lists for each element how often it occurs in the world. Selecting an entry 83 210 * calls SelectionAtomByElementAction to select all atoms of that particular 84 211 * element. 85 212 * 86 * I t observes the World and performs a complete refill on any message. To reduce87 * per formance issues it marks the list as dirty and refills it the next time the88 * GUI is idle. This way many successive changes to the world only lead to a89 * single refill.213 * Initially, it fills itself by looking at all elements in the World's 214 * periodentafel. It also listens to AtomObserver's ElementChanged to know 215 * when to update a certain element in its list. By using an internal list 216 * for each atom's element, it can update each element's occurrence. 90 217 * 91 218 * \section QtMoleculeList … … 94 221 * Selecting an entry calls the SelectionMoleculeByIdAction. 95 222 * 96 * It observes the World the same way QtElementList does. 223 * The QtMoleculeList is also a rather complex beast. It is a tree of 224 * rows and each row consists of a number of elements. There are two 225 * levels, the group level where the common formula for all molecules 226 * is given, and the molecule level where are molecules of this specific 227 * formula are summarized. 228 * 229 * The group items are QStandardItems. Sadly, they are not derived from 230 * QObject and hence do not use the S/S system. The group items are 231 * directly controlled by the QtMoleculeList. 232 * 233 * However, the molecule items are different. They are derived from 234 * QtMoleculeList and use an ObservedValue internally to contain an always 235 * valid copy of the required information. They inform the QtMoleculeList on 236 * updates via a callback (as QStandardItem, from which they are also derived, 237 * does not use the S/S system). The callback takes care of then also updating 238 * the group items and possibly moving the molecule items around, e.g. if 239 * their formula has changed they suddenly belong to another group. 240 * 241 * All items are instantiated by the QtMoleculeItemFactory. 242 * 243 * QtMoleculeList uses an internal QTimer to only update itself at regular 244 * intervals. Hence, updates are processed rather lazily. We keep lists 245 * of changes, separated for group and molecule items. And these are processed 246 * one after the other at the intervals dictated by the QTimer in 247 * updateItemStates(). 97 248 * 98 249 * \section QtShapeController … … 119 270 * they automatically clear the info box. 120 271 * 121 * \date 201 3-02-22272 * \date 2015-07-15 122 273 */
Note:
See TracChangeset
for help on using the changeset viewer.