PDA

View Full Version : How to make dynamic cavas controlled by socket



beggingqt
25th September 2017, 11:00
Hello,

I want to make a canvas that I can control from a external socket.

Assume the program listens to port 1234

Then I'd like to send sequences of messages to Port 1234 which would contain commands
to manipulate the canvas

For example (in some syntax)

/add_canvas line X1, Y1, X2, Y2 ...
/add_circle X,Y,R

etc. I'd also like to add things like buttons to the canvas
/add_button X,Y,W,H,"click"

and be sent messages (to the controlling socket) when the user clicks on the button.

Instead of having the entire control of the widget in one place - I'd like to
separate them into a client and server with the server doing the graphics
and the client (on a different machine) doing the control.

I realise that these commands would have to be encoded in some sense (ie as JSON, XML)
and framed (I'm assuming TCP) so to avoid fragmentation I'd need to add some
framing information.

What would be the best way to write this?

Suppose the input commands were JSON containing embedded javascript type canvas
plotting commands - would this be easy to implement? If so How?

Thanks

d_stranz
25th September 2017, 18:48
I would start by looking at this Qt client-server example (https://doc.qt.io/qt-5/qtnetwork-fortuneserver-example.html). You basically want to abstract the communications protocol away from whatever the application is doing with the strings being passed in the protocol. I would also abstract the actual format of the commands and replies (XML, JSON, whatever) away from the commands themselves. That is, the "addCircle" command is called by some other abstraction that deals with the actual string passed in. And how that abstraction actually gets that string should be independent of the protocol used. You should be able to write this entire thing so it is independent of whether the client and server are separate programs or where they execute, or even if it is a client-server at all.

So you'll have things like Canvas and Scene classes (for which the Qt Graphics Scene / View architecture should work), you'll have a set of classes derived from an abstract Command class, you'll have an abstract CommandParser base class whose job it is to take a string from an abstract CommandReceiver class, parse it, and turn it into a concrete Command subclass instance that then calls into a SceneManager, for example.

In the simplest case, you could have an ASCII file that contains a list of strings, and your concrete CommandReceiver class could simply read that file, line-by-line and pass each one to the CommandGenerator. That lets you develop and test the command format and execution protocol without all the overhead of TCP/IP, sockets, and the rest. When that part is working, then you can yank out the file-based commands and replace them with something more interactive, like a command line interface that can deal with typos and the rest. Finally, when everything works standalone, you can bolt on the TCP/IP part.

You should be able to draw a diagram of this entire thing in a way that none of the classes depends in any way on how those classes are actually implemented. And if you can do that, then you can implement each piece independently of the others, using throwaway code to represent those other parts. Work on the interfaces between the different parts rather than thinking about the implementation of the interfaces and you'll end up with a flexible system that is easy to implement, debug, and add to.

And of course, you'll use custom signals and slots everywhere so that no object needs a pointer to any other object or even needs to know if any other object is even listening.

beggingqt
25th September 2017, 19:21
I'm familiar with the Client-Server part of the problem, so reading a TCP socket is not a problem.

All the examples I've read have sequences of draw commands in the code.

For example in QML I could write

onPaint:
{
var x = 140
var y = 140
var radius = 140;
var startangle = -90
var endangle = 30
var context = getContext("2d");
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, (startangle)*(Math.PI/180), (endangle)*(Math.PI/180), false) //x, y, radius, startAngle, endAngle, anticlockwise
context.fillStyle = "blue"
context.fill();
context.closePath();
}

What I want to do is receive a message (say In Json) it might be
{type:'draw_arc', x:140, y:40, ...}

Then on receipt of the message draw the arc.

Do really have to put all the received draw commands in an array, and iterate down it inside an onPaint event.

How often is the onPaint triggered?

Can't I draw once onto a bitmap - then recover the bit map most of the time.

In pseudo code I'd write

onPaint:
for(i in things){
draw( things[i] )
}

does my draw(thing) have to be a massive switch statement that special cases into
the different low level commands. ie. in pseudo code

function draw(x){
switch(x.type){
case 'arc': {
ctx.begin();
ctx.move(x.c, x.y);
...
break;
}

I guess I could do this - but I was wondering if this kind of code was hidden away
in a library somewhere ...

I can imagine the QML code to be statically compiled - to the onPaint just pointed into
code - but I need a dynamic interface where I can change the command in the program

All the code that I need would appear to have been written but not interfaced in the
way I'd like.

d_stranz
25th September 2017, 21:30
Do really have to put all the received draw commands in an array, and iterate down it inside an onPaint event.

That's one way to do it.


Can't I draw once onto a bitmap - then recover the bit map most of the time.

and that's another way


does my draw(thing) have to be a massive switch statement that special cases into the different low level commands.

and you could do this, too, -or-


but I was wondering if this kind of code was hidden away in a library somewhere ...

You mean a library like the Qt Graphics / View library, that uses QGraphicsScene to store a bunch of QGraphicsItem subclass instances that know how to draw themselves, and QGraphicsView, where the scene can tell all of these objects to draw themselves? That's the way I would implement the canvas side of it.

In the G/V architecture, the scene causes all views onto it to redraw themselves any time the scene changes. Views will also redraw if their viewport onto the scene changes. All of this is automatic and you do not have to implement any painting code yourself unless you create custom graphics items.

Qt also has an architecture for commands that supports undo and redo, so if you want your drawing system to have that capability you don't have to invent that wheel either.