Using Tchart in c++ to draw a vertical line - c++

I got some values that i need to draw as a vertical line. The line should be from begin till the end of diagramm field.
I use VCLTee.Chart.hpp in Embarcadero. As I know it is the Tchart, that is actually used more for Delphi.
However:
I use this function:
DlgMainWindow->ChartTemperatureCurve->Canvas->DoVertLine(XValue,YValue,ZValue);
i canĀ“t find the description. As I see DoVertLine works with Pixel of the diagramm. But if my YValue = 10 , and should be always parallel to x for whole distance.

You should convert your YValue from axis values to pixels with the axis CalcPosValue function.
If you want to draw a line at a constant YValue, it would be an horizontal line, not a vertical line.
In the following example I'm drawing an horizontal line at YValue=10.
Note the drawing functions should be called at OnAfterDraw event or similar to make sure your custom drawings are done after every repaint.
To use OnAfterDraw event on RAD Studio, select the chart at design-time, navigate to the Events tab at the Object Inspector and double-click on the white cell next to OnAfterDraw.
This action should open the code view with the cursor inside a new and empty OnAfterDraw function.
Then you can add what you want to do there. Ie, drawing an horizontal line within the ChartRect, at YValue=10:
void __fastcall TForm1::Chart1AfterDraw(TObject *Sender)
{
Chart1->Canvas->Pen->Color = clRed;
int X0Pos = Chart1->ChartRect.Left;
int X1Pos = X0Pos + Chart1->ChartRect.Width();
double YVal = 10;
int YPos = Chart1->Axes->Left->CalcPosValue(YVal);
Chart1->Canvas->DoHorizLine(X0Pos, X1Pos, YPos);
}

Related

glReadPixels doesnt work for the first left click

I am working on a MFC app which is a MDI. One of the child frame uses OpenGL(mixed with fixed function and modern version) called 3d view and another child frame uses GDI called plan view. Both of the views use the same doc.
The 3d view has a function to detect if the mouse cursor is over rendered 3d model by reading pixels and check its depth value.
The function is used for WM_MOUSEMOVE and WM_LBUTTONDOWN events. Most time it works pretty well. But it failed when I move my cursor from the plan view(currently active) to the 3d view and left mouse click. The depth values read from the pixels(called from onLButtonDown) are always all zeros though it is over a model. There is no OpenGL error reported. It only fails on the first mouse click when the 3d view is not activated. Afterwards, everything works well again.
The issue doesn't happen on all machines. And it happens to me but not to another guy with the same hardware machine with me. Is that possible hardware related or a code bug?
Things tried:
I tried to increase the pixel block size much bigger but depths are still all zero.
If I click on the title bar of the 3d view to activate it first, then works.
I tried to set the 3d view active and foreground in the onLButtonDown method before reading pixels. But still failed.(btw, the 3d view should be active already before the OnLButtonDown handler via other message handler fired by the left button down).
I tried to invalidate rect before reading pixels, failed too.
The code is as below:
BOOL CMy3DView::IsOverModel(int x0, int y0, int &xM, int &yM, GLfloat &zWin, int width0 , int height0 )
{
int width = max(1,width0);
int height= max(1,height0);
CRect RectView;
GetClientRect(&RectView);
GLint realy = RectView.Height() - 1 - (GLint)y0 ; /* OpenGL y coordinate position */
std::vector<GLfloat> z(width*height);
//Read the window z co-ordinates the z value of the points in a rectangle of width*height )
xM = max(0, x0-(width-1)/2);
yM = max(0, realy-(height-1)/2);
glReadPixels(xM, yM, (GLsizei)width, (GLsizei)height, GL_DEPTH_COMPONENT, GL_FLOAT, &z[0]); OutputGlError(_T("glReadPixels")) ;
/* check pixels along concentric, nested boxes around the central point */
for (int k=0; k<=(min(height,width)-1)/2; ++k){
for (int i=-k;i<=k;++i){
xM = x0+i;
for (int j=-k;j<=k;++j){
if (abs(i)==k || abs(j)==k) {
yM = realy+j;
zWin=z[(i+(width-1)/2)+width*(j+(height-1)/2)];
if (zWin<1.0-FLT_EPSILON) break;
}
}
if (zWin<1.0-FLT_EPSILON) break;
}
if (zWin<1.0-FLT_EPSILON) break;
}
yM = RectView.Height() - 1 - yM;
if (zWin>1.0-FLT_EPSILON || zWin<FLT_EPSILON) {// z is the depth, between 0 and 1, i.e. between Near and Far plans.
xM=x0; yM=y0;
return FALSE;
}
return TRUE;
}
Just found a solution for that: I called render(GetDC) before any processing in OnLButtonDown. somehow it fixed the issue though I don't think it's necessary.
InvalideRect wont fix the issue since it will update the view for the next WM_PAINT.
Weird, since it works for some machines without the fix. Still curious about the reason.

Change Cursor Image While Hovering Over An Object Drawn At OpenGL And Displaying Object's Variables

I am currently working on a project that I use C++, OpenGL, Qt 5.9.2 and Microsoft Visual Studio Professional 2015 on a 64 bit Operating System, Windows 10 Pro.
I have a user interface that I have created and in that user interface, there is a QGLWidget, that I am using for draw processes, with other widgets like push buttons and a dockWidget. I have a class Ball and it has variables(distance(double) and angle(int)) that determines where an instance of that Ball is going to be drawn inside the QGLWidget. Ball class has got 2 more variables that is, id(int), model(String) and year(int) Every other draw process draws lines except Ball drawings.
Drawings are 2 dimensional.
Every Ball has the same color(rgb)!
First problem: I want to left click to one of the Ball instances and I want to display it's id, model and year at The dockWidget.
Second Problem: While doing the stuff that I have mentioned at the First Problem section. I want the cursor image to change while hovering above any of the Ball instances, and change back to default Windows mouse cursor while not.
I have created a function that checks if the MouseEvent is LeftClick:
void DisplayManager::mousePressEvent(QMouseEvent* ev) {
if (ev->buttons() & Qt::LeftButton) { // Balls Are Green
if(// CHECK IF THERE IS A BALL AT THE CLICKED COORDINATES) {
// DISPLAY THE X and Y OF THE BALL AT THE DOCK WIDGET
}
}
}
This is my initializeGL function: (DisplayManager is the name of my QGLWidget)
void DisplayManager::initializeGL() {
glEnable(GL_COLOR_MATERIAL); // Enables the changing of the draw color with glColor() functions
glColor3f(0.0, 1.0, 0.0);
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1); //sets a black background 1 0 0 1
}
On the basis this is a Picking problem and there are several information about it at the internet but I am not using GLUT and I am not using any shader. So in the light of all these I was unable to find any effective solution or clue about how can I accomplish all that I want.
I would be really glad if someone could help me with at least one of these problems.
I have currently finished working with the project. I thought that I should provide an answer to my question in case someone with a similar problem comes across with my question in the future.
void DisplayManager::mousePressEvent(QMouseEvent* ev) {
// The processes that are being executed after a left mouse button click on the DisplayManager.
if (ev->buttons() & Qt::LeftButton) {
double aspectRatio = openGLWidgetWidth / openGLWidgetHeight;
int xOfClicked = ev->x() - (openGLWidgetWidth / 2);
int yOfClicked = - (ev->y() - (openGLWidgetHeight / 2));
// The variable to be used for calculating fault tolerance of the click event.
int distanceBetweenPressAndDraw = 0;
// Executes the processes inside for every ball in vector.
for (int i = 0; i < ballVector.length(); i++) {
// Calculates the screen coordinates of the i'th ball.
int rangeOfBallInScreenDistance = rangeToScreenDistance(ballVector.at(i).range);
double screenXOfBall = rangeOfBallInScreenDistance * sin(ballVector.at(i).degree * DEGTORAD);
double screenYOfBall = rangeOfBallInScreenDistance * cos(ballVector.at(i).degree * DEGTORAD);
// Calculates the distance between pressed position and the i'th ball according to the screen coordinates.
distanceBetweenPressAndDraw = sqrt(pow((screenXOfBall - xOfClicked), 2) + pow((screenYOfBall - yOfClicked), 2));
// Decides if the clicked position is a ball (considering the fault tolerance).
if (distanceBetweenPressAndDraw < 10) {
emit printXY(QPointF(xOfClicked, yOfClicked)); // Prints the screen coordinates of the clicked positions (At the Dock Widget inside Main Window).
}
}
}
}
This was the solution for my First Problem. I would be glad though if someone could answer my Second problem in a comment or answer somehow.

qt convert mouse position to chart coordinate system

I would like to display a callout on a QChart with a QBarSeries displayed.
I'm struggling in how to convert the position of my mouse to the qchart coordinate frame, so that I can use it as Anchor in my callout.
I would like to set it during my
MainWindow::barSeriesHovered(bool status, int index, QBarSet *barset){}
event.
I managed to do it using following code:
auto point = QCursor::pos();
point = myChartView->mapFromGlobal(point);
auto pointF = myChartView->mapToScene(point);
pointF = myChartView->chart()->mapFromScene(point);
pointF = myChartView->chart()->mapToValue(point,myChartView->chart()->series().at(0));
myCallout->setAnchor(pointF);
maybe not the most efficient use, but yes, it works
Another drawback is, that it always appears at the border of a bar, and does not move with your mouse cursor while you move around inside the bar, but yes, it works

Highlighting TGrid row in code

I have a custom TGrid control which I am trying to make it so when the mouse hovers over a row, that row is highlighted. Rows are automatically highlighted if I used the arrow keys to navigate the grid. However, I am not sure how to replicate this effect for navigation with the mouse.
Currently, I have a MouseMove function which can detect which row of the grid the mouse is hovering over.
void __fastcall TFmSearchBar::GridMouseMove(TObject *Sender, TShiftState Shift, float X, float Y)
{
int rowSelected = FGrid->RowByPoint(X, Y);
if(rowSelected >= FGrid->RowCount)
rowSelected = FGrid->RowCount - 1;
if(rowSelected != -1)
{
FGrid->SelectRow(rowSelected);
}
}
I originally thought using the SelectRow function would achieve the desired effect, however nothing happens when that method is used. Additionally I have tried using
FGrid->SelectCell(0, rowSelected);
which did not work either.
I have verified that I am getting the right row from the function by setting a row's text to bold when the mouse hovers over it using
FGrid->RowObjects[rowSelected]->SetBold();
you must enable following options for TGrid component:
1) RowSelect = True
2) AlwaysShowSelection = True
Tested with Delphi XE8 -- works fine. My code:
procedure TForm1.Grid1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
Grid1.SelectRow(Grid1.RowByPoint(X, Y));
end;
if you want, i could provide you DFM file either.

Drawing Dice in a Windows C++ program?

We just started learning windows programming in C++. We have to make a program that has 4 die on the screen, and when the user presses 'SpaceBar', the die roll, or the number of dots on the die change randomly. Our professor hasent given us a lot of information, so I am kind of just looking for some direction.
Right now, I have 4 squares drawn on the screen, made with the Rectangle() function.
Rectangle(hDC,30,100,130,200);
Rectangle(hDC,180,100,280,200);
Rectangle(hDC,330,100,430,200);
Rectangle(hDC,480,100,580,200);
My question is 1) how would I go about drawing dots on these 'squares' and not on the 'screen'. So if I move the die upwards, the dots move with the square and dont just stay stationed painted on the screen. And 2.) How would I go about making those dots randomly change when spacebar is pressed (simulating that they have been rolled)?
Just looking for some direction, thanks.
1)
You will still have to draw them on the screen, but you can structure your program to realize the dots as part of the square.
void moveSquare()
{
//change square position
//change dots positions the same as you changed the square
}
2)
You can capture keypresses in your window with the WM_KEYDOWN and WM_KEYUP messages, or the WM_CHAR message. Just start a chain of changing how many dots are supposed to appear on the die when space is pressed (SetTimer could be handy), and let WM_PAINT do the work of painting the dots (or call something to calculate the positions of the dots, and let WM_PAINT loop through each dot it needs to draw.
void OnSpacePressed()
{
//start changing dots every so often, handled elsewhere
//maybe check if finished rolling before doing so
}
void calculateDotPositions()
{
switch (numberOfDots) {...} //hint: use the square as a reference point
}
void OnPaint()
{
//paint each sqaure
//paint each dot in the correct position, which should be updated with square
}
void OnChangeDots()
{
//change number of dots
//also start a new change to happen later if not done rolling
}
For drawing dots, use Warren P's reference link.
Another method is to create a bitmap or picture in memory. One for each of the 6 faces of the die. The objective here is to copy the bitmaps to the screen, rather than having to redraw them each time. Research "bitmap", and "bitblt".
You should make a routine that draws a die at the origin, offset by given coordinates. I'm not familiar with the particular library you are using, so I don't know what hDC is, but it should look something like the following.
void drawDie(HDC hDC, int xCoord, int yCoord, int dieValue)
{
Rectangle(hDC, -50 + xCoord, -50 + yCoord, 50 + xCoord, 50 + yCoord);
// draw some number of circles specified by dieValue at appropriate coordinates
// translated by xCoord and yCoord arguments
}
Then you can just redraw dice over your previous ones if you want them to change.