I am currently building an editor with Eclipse GEF. It is possible to add new parts via the editor and rename them.
However I have a little problem with the moving of the elements. When dragging them with the mouse they are not moved when I release the mouse and the element doesn't collide with another one.
The positions of the elements are stored in an EMap (the model is made with EMF). Changes in the view are saved with the put method of the map.
While going through it with the debugger I noticed that the command is executed, but the view is not refreshed yet.
I added an adapter to the model, but its notifyChanged is not called from the system.
public class ViewAdapter implements Adapter {
#Override
public void notifyChanged(Notification notification) {
refreshVisuals();
}
}
The ViewAdapter is registered in the activate method of the EditPart.
What could it be?
As you are working with a map the normal Adapter interface won't work, because it only listens to adds or removals of map entries.
If you want to listen on changes of map elements, you should use an EContentAdapter instead:
public class ViewAdapter extends EContentAdapter {
#Override
public void notifyChanged(Notification notification) {
refreshVisuals();
super.notifyChanged(notification);
}
}
It is important that you call the super method so the notifications of the map entries are forwared to the map itself.
Related
Right up-front, I'll apologize: This is a monster question, but I wanted to provide what I hope is all of the pertinent details.
I've got a QML-based GUI that I was tasked with taking over and developing from proof-of-concept to release. I believe the GUI is based on an example provided by QT (Automotive, maybe?). The GUI is being compiled for web-assembly (emscripten) and features a "back-end data-client" which communicates with our hardware controller via a socket and communicates with the GUI via signals. The GUI is accessed via web browser and communicates with the Data_Client via QWebSocket.
The GUI proof was initially created with a very "flat" hierarchy where every element is created and managed within a single ApplicationWindow object in a single "main" QML file. A Data_Client object is instantiated there and all the other visual elements are children (at various levels) of the ApplicationWindow:
ApplicationWindow {
id: appWindow
//various properties and stuff
Item {
id: clientHolder
property Data_Client client
}
ColumnLayout {
id: mainLayout
anchors.fill: parent
layoutDirection: Qt.LeftToRight
//And so on...
The Data_Client C++ currently emits various signals in response to various things that happen in the controller application. In the main .QML the signals are handled as follows:
Connections {
target: client
onNew_status_port_data:
{
textStatusPort.text = qdata;
}
onNew_status_data_act_on:
{
imageStatusData.source = "../imagine-assets/ledGoodRim.png";
}
//and so on...
What I'm trying to do is create a ChannelStatusPanel object that holds the various status fields and handles the updates to those fields (text, images, etc.) when it receives information from the Data_Client backend. There are multiple instances of this ChannelStatusPanel contained in a MainStatusPanel which is made visible or not from the main ApplicationWindow:
Having said all of that (Phew!), I come finally to my question(s). What is the correct way to signal a specific instance of the ChannelStatusPanel object from the Data_Client with the various data items needed to drive changes to the visual elements of the ChannelStatusPanel?
I thought I was being clever by defining a ChannelStatusObject to hold the values:
Item {
id: channelStatusObject
property int channel
property int enabled //Using the EnabledState enum
property string mode
property int bitrate
property int dataActivity //Using the LedState enum
//and more...
property int packetCount
}
In the ChannelStatusPanel.qml, I then created a ChannelStatusObject property and a slot to handle the property change:
property ChannelStatusObject statusObject
onStatusObjectChanged: {
//..do the stuff
From the Data_Client C++ I will get the information from the controller application and determine which "channel" I need to update. As I see it, I need to be able to do the following things:
I need to determine which instance of ChannelStatusPanel I need to update. How do I intelligently get a reference to the instance I want to signal? Is that just accomplished through QObject::findChild()? Is there a better, faster, or smarter way?
In the Data_Client C++, do I want to create an instance of ChannelStatusObject, set the various fields within it appropriately, and then set the ChannelStatusPanel instance's ChannelStatusObject property equal to the newly created ChannelStatusObject? Alternatively, is there a mechanism to get a reference to the Panel's ChannelStatusObject and set each of its properties (fields) to what I want? In C++, something like this:
QQmlComponent component(&engine, "ChannelStatusObject.qml");
QObject *statObj= component.create();
QQmlProperty::write(statObj, "channel", 1)
QQmlProperty::write(statObj, "bitrate", 5000);
QQmlProperty::write(statObj, "enabled", 0);
//Then something like using the pointer from #1, above, to set the Panel property
//QObject *channelPanel;
QQmlProperty::write(channelPanel, "statusObject", statObj)
Is there some other, more accepted or conventional paradigm for doing this? Is this too convoluted?
I would go about this using Qt's model-view-controller (delegate) paradigm. That is, your C++ code should expose some list-like Q_PROPERTY of channel status objects, which in turn expose their own data as properties. This can be done using a QQmlListProperty, as demonstrated here.
However, if the list itself is controlled from C++ code -- that is, the QML code does not need to directly edit the model, but only control which ones are shown in the view and possibly modify existing elements -- then it can be something simpler like a QList of QObject-derived pointers. As long as you do emit a signal when changing the list, this should be fine:
class ChannelStatus : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(int channel READ channel CONSTANT)
Q_PROPERTY(int enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
// etc.
};
class Data_Client : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QList<ChannelStatus*> statusList READ statusList NOTIFY statusListChanged)
// ...
};
The ChannelStatus class itself must be registered with the QML type system, so that it can be imported in QML documents. Additionally, the list property type will need to be registered as a metatype, either in the main function or as a static variable. Otherwise, only lists of actual QObject pointers are recognised and you would have to provide yours as such.
qmlRegisterUncreatableType<ChannelStatus>("LibraryName", 1, 0,
"ChannelStatus", "Property access only.");
qRegisterMetaType<QList<ChannelStatus*>>();
You then use this property of the client on the QML side as the model property of a suitable QML component, such as a ListView or a Repeater inside a container like RowLayout. For example:
import LibraryName 1.0
ListView {
model: client.statusList
delegate: Column {
Label { text: modelData.channel }
Image { source: modelData.enabled ? "foo" : "bar" }
// ...
}
}
As you can see, the model data is implicitly attached to the delegate components. Any NOTIFYable properties will have their values automatically updated.
Below is how I've setup my application.
Front-end is in QML. Back-end is in Qt C++. H/W Controller application is in C.
In Qt C++ back-end, I have QObject derived database and databasePoint classes.
database object holds a QMap of databasePoint objects.
Each databasePoint object has a unique point name, which is used as an identifier.
database object is created in main.cpp and exposed to QML as a context property.
database class has a method to return a pointer to databasePoint object.
In QML, this method is used to create databasePoint objects.
When this method is called, a databasePoint object is created and added to QMap if it doesn't already exist.
databasePoint class has read-write value properties.
These properties are used for communication between UI, back-end and controller.
In a timer, latest value is polled from controller periodically, whenever there's a change, the value property is updated.
When the value property is updated from UI, the value is written to controller.
class database : public QObject
{
public slots:
databasePoint* getDbpointObject(QString pointName);
private:
QMap<QString, databasePoint*> dbPointMap;
};
class databasePoint : public QObject
{
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
public:
QVariant value(void);
void setValue(QVariant value);
QVariant my_value;
signals:
void valueChanged();
};
DatabasePointComponent.qml:
Item {
required property string pointName
property var pointObj: database.getDbpointObject(pointName)
}
MyScreen.qml:
DatabasePointComponent{
id: dbTEMP
pointName: "TEMP"
}
TextInput {
text: dbTEMP.pointObj.value
onAccepted: dbTEMP.pointObj.value = text
}
I've run into a bit of an issue related to a whitelist Web Browser my company has been developing / maintaining for one of our product lines. The browser runs on top of Qt 4.8.6, using qtwebkit (Migration to 5.X would be ideal, but the embedded Linux OS we're using is too old to support the newer versions based on our testing, and upgrading to a newer OS is too costly to us / our customers). The primary interface to the browser is a 6x8 touchscreen, mounted inside an aircraft cockpit.
For sites that have things like scrollable/embedded maps (ex. Google Maps), the users of the browser want the ability to drag the entire page when they are selecting something outside of the map, and drag just the map (without the entire page scrolling) when the map is selected (Ala most of the popular mobile browsers).
Thus far, I am able to do one or the other, but not both:
When I hook mouse handlers into a QWebView or QGraphicsWebView, I can turn the cursor into a hand and very easily support dragging of the entire web page. However, that inhibits the page's ability to handle the mouse events for when a user is pulling over a map (i.e. When a user drags over a map, it drags the entire page without moving the map).
When I don't add in the hooks to handle mouse events, things like maps are scrollable by grapping/dragging them, but of course the user loses the ability to drag the entire page.
Right now, the browser uses the later, with scroll bars disabled and a directional-arrow overlay to allow the user to scroll the entire page (as the display size is limited, and scrollbars take up too much space when they are sized large enough for the user to interact with them)...but this is not ideal.
My Question: Is there any easy way to make it so that the page, and elements in a page, can be scrolled seamlessly?
Thanks!
Rob
Seems to me like you need to check if you are over such a map and ignore(pass along) the event in that case. I think you should be able to do something like this:
bool GraphicsWebView::isOverMap(QPoint pos) {
QWebPage* webPage = this->page();
if (webPage) {
QWebFrame* webFrame = webPage->frameAt(pos);
if (webFrame) {
QString selectorQuery = "#map-canvas"; // Based on https://developers.google.com/maps/tutorials/fundamentals/adding-a-google-map
QList<QWebElement> list = webFrame->findAllElements(selectorQuery).toList(); // Find all the maps!
foreach(QWebElement element, list) {
if (element.geometry().contains(pos)) {
return true; // Cursor is over a map
}
}
}
}
return false; // No match
}
Obviously this is a pretty specific function but there is probably a way to come up with a better selector query that will apply to all those kinds of QWebElement.
Assuming you hook mouse events by subclassing QGraphicsWebView and reimplementing void mouseMoveEvent(QGraphicsSceneMouseEvent * event), I suggest you do something like:
void GraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
if (isOverMap(mapFromScene(event->scenePos()).toPoint())) { // We got a map!
event.ignore(); // Clear the accept flag
return; // Return, we're done here
}
handleMoveView(); // Not over any maps, let's scroll the page
}
This part of the doc explains how events are handled with regard to the topmost item. I especially recommend you read the third paragraph.
Hope that helps!
EDIT: Did a bit more research and it looks like something like that could be more generic:
graphicsView.focusItem()->flags().testFlag(QGraphicsItem::ItemIsMovable);
It's at the very least worth investigating as a replacement to isOverMap()
EDIT: Gotcha, here is something you can try then.
Start by subclassing QGraphicsSceneMouseEvent and add a signal called void destroyedWithoutAccept() that's emitted in the destructor if the event has not been accepted.
Then modify mouseMoveEvent to look like this:
void GraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
MyEvent myEvent = new MyEvent(event); // Copy event
event.accept(); // accept original event
connect(myEvent, SIGNAL(destroyedWithoutAccept),
this, SLOT(handleMoveView)); // Callback if unused
QGraphicsWebView::mouseMoveEvent(myEvent); // Pass it to Base class
}
If that works, it might introduce a bit of delay if deleteLater is used to destroy it. But in that case reimplement it as well.
I'm building a heads up display for OBD data (speed, RPM, throttle position etc.) using Glass.
I am using a LiveCard to display the HUD, but like all cards it fades away after a few seconds as Glass puts the display to sleep.
Is there a way to force the card to remain visible until it's dismissed? A HUD display isn't very useful if it keeps needing to be woken up.
The code thus far is here: https://github.com/mpicco/glass-obd-hud.
Thanks,
Marty
I'd would recommend using an Immersion + the FLAG_KEEP_SCREEN_ON flag or getting a partial wakelock within your Service.
From the Android documentation:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
wl.acquire();
// ..screen will stay on during this section..
wl.release();
If you do use the wakelock solution, do not forget to release it once your Service is stopped.
The way I've done this is inside the activity that I wish to keep the screen on for, I've added a window parameter like so:
public class MyActivity extends Activity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
The power manager service would likely work just as well, but this way when the user destroys my activity or other such things, I don't have to worry about maintaining state.
When a fling happens in a CardScrollView, I see the "zoomed out" view of a long list of cards scrolling by. This part works fine as in the code below:
mCardScrollView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (mSimulatedScrollBar != null)
mSimulatedScrollBar.setScrollPosition(position);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
However, the problem is I don't receive any update when this is happening in the OnItemSelectedListiner until the fling stops. The problem this causes is the list scrolls but until it "settles" I don't get any update on the list progress and thus can't respond in the foreground with a progress view.
There are a number of listeners and protected methods for CardScrollView, do any provide this functionality?
There currently aren't any methods or listeners that give you access to the finer scroll details of the view — only events when the user settles on a card or begins scrolling.
If you'd like to see a feature like this, please file a request in our issue tracker.
I was studying the Model-View-Controller design pattern and i understand the concept behind the pattern theorotically, but I wanted to get a peek at how one would actually put it to practice.
Wikipedia mentions Wt - Web toolkit, CppCMS and some other standard implementations which use the pattern however I have not been familiar with these, and I was just hoping and
will be really grateful If anyone can provide some sample code(hopefully C++) which implements the pattern and explains the theory of the pattern being put to practice.
Here's a quick example I made (didn't try compiling it, let me know if there's errors):
class Button; // Prewritten GUI element
class GraphGUI {
public:
GraphGUI() {
_button = new Button("Click Me");
_model = new GraphData();
_controller = new GraphController(_model, _button);
}
~GraphGUI() {
delete _button;
delete _model;
delete _controller;
}
drawGraph() {
// Use model's data to draw the graph somehow
}
...
private:
Button* _button;
GraphData* _model;
GraphController* _controller;
};
class GraphData {
public:
GraphData() {
_number = 10;
}
void increaseNumber() {
_number += 10;
}
const int getNumber() { return _number; }
private:
int _number;
};
class GraphController {
public:
GraphController(GraphData* model, Button* button) {
__model = model;
__button = button;
__button->setClickHandler(this, &onButtonClicked);
}
void onButtonClicked() {
__model->increaseNumber();
}
private:
// Don't handle memory
GraphData* __model;
Button* __button;
};
Ignoring the implementation of Button, basically this program will use GraphGUI to display a graph that will change when a button is pressed. Let's say it's a bar graph and it will get taller.
Since the model is independent of the view (the button), and the controller handles the communication between the two, this follows the MVC pattern.
When the button is clicked, the controller modifies the model via the onButtonClicked function, which the Button class knows to call when it is clicked.
The beauty of this is since the model and view are completely independent, the implementation of each can drastically change and it won't affect the other, the controller might simply have to make a few changes. If the model in this case calculated some result based off some database data, then clicking the button could cause this to happen, but the button implementation wouldn't have to change. Or, instead of telling the controller when a click occurs, maybe it can tell the controller when the button is moused-over. The same changes are applied to model, regardless of what triggered the changes.
A simple text editor could be designed based on MVC. Think of the string class as the model, where data is stored. We might have a class called SimpleTextView which displays the text in the string attached to it, as it is. A class called KeyboardEventHandler can act as the controller. The controller will notify the view about new keyboard events. The view in turn modifies the model (like appending or removing text). The changes in the model is reflected on all views attached to it. For instance, there might be another view called HtmlView attached to the string object manipulated from within the SimpleTextView. If the user enters valid HTML tags in the SimpleTextView, the HtmlView will display the formatted output - real-time.
There are couple of complete MVC examples, plus discussion, in ch 2 of an introduction to programming in Python 3.x that I wrote (I've not completed ch 3 etc., that project's been on ice for some time -- Python community really like angry swarm of bees when discovered I'd written that Python was perhaps not suitable for very large scale development, so it became difficult to get sensible feedback). It's available in PDF format from Google Docs. I don't know how well it maps to common MVC implementations, I was mostly concerned with getting the general idea across. :-)
Cheers & hth.,
PS: There's a nice table of contents in the PDF file but Google Docs doesn't show it. You'd need to dl and use Foxit or Acrobat or some other PDF viewer. I think there's a separate viewable TOC at Google Docs, though, haven't checked and don't remember whether updated.
PPS: Forgot to mention, the MVC image processing example near the end has nice pic of Lena Söderberg! :)
Code is the best approach to understand and learn Model View Controller:
Here is a simple JS example (from Wiki)
/** Model, View, Controller */
var M = {}, V = {}, C = {};
/** Model stores data */
M.data = "hello world";
/** View controls what to present */
V.render = (M) => { alert(M.data); }
/** Controller bridges View and Model */
C.handleOnload = () => { V.render(M); }
/** Controller on Windows OnLoad event */
window.onload = C.handleOnload;
Here is a detailed post in C/C++
Model-View-Controller Explained in C++