Q3DSurface - define a simple Graph - qt

I am really new to Qt-coding (and coding in general) and would like to plot a numeric function. I thought the best tool/class to use would be Q3DSurface.
Unfortunately I can not even define a simple graph. I tried to use that example
https://doc.qt.io/qt-5/qtdatavisualization-surface-example.html
but I am not even able to write the following line from the main.cpp
Q3DSurface *graph = new Q3DSurface();
Obviously there is no constructor without arguments in the version 5.9.
This is my attempt so far:
using namespace QtDataVisualization;
Surface::Surface()
{
QSurfaceFormat* format= new QSurfaceFormat();
QWindow * window= new QWindow(Q_NULLPTR);
Q3DSurface* m_pGraph= new Q3DSurface(format, window);
}
The constructor is defined as
Q3DSurface(const QSurfaceFormat *format = Q_NULLPTR, QWindow *parent = Q_NULLPTR).
This attempt isn't working. Do you have an idea how I could create a new object of Q3DSurface?

Related

Using GraphView Library for functions to display multiple graphs

I'm currently developing an android app for reading out multiple sensor values via Bluetooth and display them in a graph. When I stumbled upon jjoe64's GraphViewLibrary, I knew this would fit my purposes perfectly. But now I'm kind of stuck. Basically, I wrote a little function that would generate and display the values of three sensors in 3 different graphs one under the other. This works just fine when the activity is started first, all three graphs a nicely rendered and displayed. But when I want to update the graphs with different values using the resetData()-method to render the new values in each graph, only the last of the three graphs is updated. Obviously, because it's the last graph generated using this rather simple function. My question is: Is there any other elegant way to use a function like mine for generating and updating all three graphs one after the other? I already tried to set the GraphView variable back to null and different combinations of removing and adding the view. Passing the function a individual GraphView-variable like graphView1, graphView2... does also not work.
Here is the function:
private GraphView graphView;
private GraphViewSeries graphViewSerie;
private Boolean graphExisting = false;
...
public void makeGraphs (float[] valueArray, String heading, int graphId) {
String graphNumber = "graph"+graphId;
int resId = getResources().getIdentifier(graphNumber,"id", getPackageName());
LinearLayout layout = (LinearLayout) findViewById(resId);
int numElements = valueArray.length;
GraphViewData[] data = new GraphViewData[numElements];
for (int c = 0; c<numElements; c++) {
data[c] = new GraphViewData(c+1, valueArray[c]);
Log.i(tag, "GraphView Graph"+graphId+": ["+(c+1)+"] ["+valueArray[c]+"].");
}
if (!graphExisting) {
// init temperature series data
graphView = new LineGraphView(
this // context
, heading // heading
);
graphViewSerie = new GraphViewSeries(data);
graphView.addSeries(graphViewSerie);
((LineGraphView) graphView).setDrawBackground(true);
graphView.getGraphViewStyle().setNumHorizontalLabels(numElements);
graphView.getGraphViewStyle().setNumVerticalLabels(5);
graphView.getGraphViewStyle().setTextSize(10);
layout.addView(graphView);
}
else {
//graphViewSerie = new GraphViewSeries(data);
//graphViewSerie.resetData(data);
graphViewSerie.resetData(new GraphViewData[] {
new GraphViewData(1, 1.2f)
, new GraphViewData(2, 1.4f)
, new GraphViewData(2.5, 1.5f) // another frequency
, new GraphViewData(3, 1.7f)
, new GraphViewData(4, 1.3f)
, new GraphViewData(5, 1.0f)
});
}
And this is the function-call depending on an previously generated array (which is being monitored to be filled with the right values):
makeGraphs(graphData[0], "TempHistory", 1);
makeGraphs(graphData[1], "AirHistory", 2);
makeGraphs(graphData[2], "SensHistory", 3);
graphExisting = true;
Any help and / or any feedback in general is greatly appreciated! Lots of thanks in advance!
EDIT / UPDATE:
Thanks to jjoe64's answer I was able to modify the function to work properly. I was clearly having a mistake in my thinking, since I thought I'd also be changing a GraphViewSeries-object I would handle my function as additional parameter (which I tried before). Of course this does not work. However, with this minor Improvements I managed to make this work using a Graphviewseries Array. To give people struggling with a similar problem an idea of what I had to change, here the quick-and-dirty draft of the solution.
I just changed
private GraphViewSeries graphViewSerie;
to
private GraphViewSeries graphViewSerie[] = new GraphViewSeries[3];
and access the right Series using the already given parameter graphId within the function (if-clause) like this:
int graphIndex = graphId - 1;
graphViewSerie[graphIndex] = new GraphViewSeries(data);
In the else-clause I'm updating the series likewise by calling
graphViewSerie[graphIndex].resetData(data);
So, once again many thanks for your support, jjoe64. I'm sorry I wasn't able to update the question earlier, but I did not find time for it.
of course it is not working correct, because you save always the latest graphseries-object in the member graphViewSerie.
First you have to store the 3 different graphviewseries (maybe via array or map) and then you have to access the correct graphviewseries-object in the else clause.

Sort QStandardItemModel in c++ Qt

I have a model of type QStandardItemModel which looks like this:
QHash<int, QByteArray> roleNames;
roleNames[Car2goVehicle::NameRole] = "plate_number";
roleNames[Car2goVehicle::DescriptionRole] = "address";
roleNames[Car2goVehicle::FuelRole] = "fuel";
roleNames[Car2goVehicle::InteriorRole] = "interior";
roleNames[Car2goVehicle::ExteriorRole] = "exterior";
roleNames[Car2goVehicle::VinRole] = "vin";
roleNames[Car2goVehicle::LatRole] = "lat";
roleNames[Car2goVehicle::LonRole] = "lon";
roleNames[Car2goVehicle::DistanceRole] = "distance";
d->m_vehiclesmodel = new RoleItemModel(roleNames);
and now I want to sort according to distance like this
d->m_vehiclesmodel->setSortRole(Qt::UserRole);
d->m_vehiclesmodel->sort(Car2goVehicle::DistanceRole, Qt::AscendingOrder);
But the result is wrong. Can somebody tell me how to sort ?
Thanks.
What's wrong with the result?
In most cases, one doesn't sort the model itself, but the view, using a QSortFilterProxyModel. Here's the example from the documentation:
QTreeView *treeView = new QTreeView;
MyItemModel *sourceModel = new MyItemModel(this);
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(sourceModel);
treeView->setModel(proxyModel);
In your example above, you might mix up roles and columns. Your Role enum should look like this:
enum Role {
NameRole=Qt::UserRole,
DistanceRole,
...
};
If you want to sort by distance role, you call:
model->setSortRole( Car2goVehicle::DistanceRole );
Then, sort by some column (which has nothing to do with the role), E.g. column 0:
model->sort( 0, Qt::AscendingOrder );
I wouldn't recommend using QSortFilterProxyModel, if QStandardItemModel::sort() is powerful enough. Instead, I stick use basic Qt signals.
Here, I'm using PyQt, but the code should also work in C++:
self.model = QStandardItemModel()
self.populate_model()
self.model.setHorizontalHeaderLabels(map(str, range(self.model.rowCount())))
self.treeview.setModel(self.model)
self.treeview.header().setSectionsClickable(True)
self.treeview.header().setSortIndicatorShown(True)
self.treeview.header().sortIndicatorChanged.connect(self.model.sort)
Notice the last line connecting QHeaderView::sortIndicatorChanged with QStandardItemModel::sort.

How can I pass controls as reference in Bada?

In the big picture I want to create a frame based application in Bada that has a single UI control - a label. So far so good, but I want it to display a number of my choosing and decrement it repeatedly every X seconds. The threading is fine (I think), but I can't pass the label pointer as a class variable.
//MyTask.h
//...
result Construct(Label* pLabel, int seconds);
//...
Label* pLabel;
//MyTask.cpp
//...
result
MyTask::Construct(Label* pLabel, int seconds) {
result r = E_SUCCESS;
r = Thread::Construct(THREAD_TYPE_EVENT_DRIVEN);
AppLog("I'm in da constructor");
this->pLabel = pLabel;
this->seconds = seconds;
return r;
}
//...
bool
Threading::OnAppInitializing(AppRegistry& appRegistry)
{
// ...
Label* pLabel = new Label();
pLabel = static_cast<Label*>(pForm->GetControl(L"IDC_LABEL1"));
MyTask* task = new MyTask();
task->Construct(&pLabel); // HERE IS THE ERROR no matching for Label**
task->Start();
// ...
}
The problem is that I have tried every possible combination of *, &, and just plain pLabel, known in Combinatorics...
It is not extremely important that I get this (it is just for training) but I am dying to understand how to solve the problem.
Have you tried:
task->Construct(pLabel, 0);
And by that I want to point out that you are missing the second parameter for MyTask::Construct.
No, I haven't. I don't know of a second parameter. But this problem is solved. If I declare a variable Object* __pVar, then the constructor should be Init(Object* pVar), and if I want to initialize an instance variable I should write
Object* pVar = new Object();
MyClass* mClass = new MyClass();
mClass->Construct(pVar);

AS 3.0 Duplicate Variable Definition

How do I resolve the error of duplicate variable definitions? There has to be
separate namespaces and use for each definition, but I'm just not seeing it.
CODE
I didn't write this, but I've been trying to unpackage it and change the classes and seem to have broken it. I want to use this for time-scaling the playback of my movies.There's cool math in here for time-scaling.
//time-scaling script
import flash.display.*;
import flash.events.Event.*;
var _time_scale:Number = .25;
var _frames_elapsed:int = 0;
var _clip:MovieClip;
function Main():void {
_clip = new SomeClip;
addEventListener(Event.ENTER_FRAME, handleEnterFrame);
//integer??
function handleEnterFrame(e:Event):void {
_frames_elapsed ++;
}
// we multiply the "real" time with our timescale to get the scaled time
// we also need to make sure we give an integer as a parameter, so we use Math.round() to round the value off
_clip.gotoAndStop(Math.round(_clip.totalFrames * _frames_elapsed * _time_scale ));
}
var myTimer:Timer = new Timer(10);
myTimer.addEventListener(TimerEvent.TIMER, timerListener);
function timerListener (e:TimerEvent):void{
ball1.rotationY += 5;/////////replace function///////////
}
myTimer.start();
ERRORS
**3596**
Warning: Duplicate variable definition.
**1151**
A conflict exists with definition _clip in namespace internal
NOTES
integers, non nested loop
It's because you are missing the ending "}" of the constructor, after this line:
addEventListener(Event.ENTER_FRAME, handleEnterFrame);
And the two following lines should probably be in your constructor, not just in the class declaration:
var myTimer:Timer = new Timer(10);
myTimer.addEventListener(TimerEvent.TIMER, timerListener);
If you are using the Timer and TimerEvent classes, you should import them:
import flash.utils.Timer;
import flash.events.TimerEvent;
Also, you don't need the .* at the end of the Event import.
Another "also". You should have access modifiers on your members ie. vars, and functions. So you should really say:
private var _clip:MovieClip;
It sounds to me like you need to look into the basics of AS3. Here is a really good starting point: http://www.actionscript.org/resources/articles/611/1/Getting-started-with-Actionscript-3/Page1.html
_clip is a reserved key word, you'll have to use something else.

Using Per Item Fills in Flex/Actionscript

I am creating a chart using mxml. The mxml tags only create a chart with a horizontal axis and vertical axis.
My result event handler has actionscript code that loops through the xml result set and creates all the series (line series and stacked bar). This part of the code works fine.
Now I need to use the functionfill function to set individual colors to each series. All the examples I have found call the functionfill from within an MXML tag, like so:
<mx:ColumnSeries id="salesGoalSeries"
xField="Name"
yField="SalesGoal"
fillFunction="myFillFunction"
displayName="Sales Goal">
I am having trouble calling functionfill from actionscript.
A portion of the code that build the data series is below:
if (node.attribute("ConfidenceStatus")=="Backlog"
|| node.attribute("ConfidenceStatus")=="Billings") {
// Create the new column series and set its properties.
var localSeries:ColumnSeries = new ColumnSeries();
localSeries.dataProvider = dataArray;
localSeries.yField = node.attribute("ConfidenceStatus");
localSeries.xField = "TimebyDay";
localSeries.displayName = node.attribute("ConfidenceStatus");
localSeries.setStyle("showDataEffect", ChangeEffect);
localSeries.fillFunction(setSeriesColor(xxx));
// Back up the current series on the chart.
var currentSeries:Array = chart.series;
// Add the new series to the current Array of series.
currentSeries.push(localSeries);
//Add Array of series to columnset
colSet.series.push(localSeries);
//assign columnset to chart
chart.series = [colSet];
My setSeriesColor function is:
private function setSeriesColor(element:ChartItem, index:Number):IFill {
var c:SolidColor = new SolidColor(0x00CC00);
var item:ColumnSeriesItem = ColumnSeriesItem(element);
//will put in logic here
return c;
}
What parameters do I put in the line localSeries.fillFunction(setSeriesColor(xxx)) ?
I tried localSeries as the first argument but I get an implicit coercion error telling me localSeries can't be cast as ChartItem.
How do I call the function correctly?
localSeries.fillFunction = setSeriesColor;
The code you have right now is actually CALLING setSeriesColor the way you have it set up. You only want it to refer to a reference of the function, not calling it, so just send it "setSeriesColor" as a variable.

Resources