So, I'm trying to acquire the x-y coordinates of the CORNERS of my MFC window...
Here's what I have so far in my draw function:
// TODO: add draw code for native data here
RECT rect;
GetClientRect(&rect);
// Get window coordinates
int left = rect.left;
int right = rect.right;
int bottom = rect.bottom;
int top = rect.top;
// Print them out
CString l;
l.Format(L"%d", left);
pDC->TextOutW(0, 100, L"Left: " + l, _tcslen(l)+6);
CString r;
r.Format(L"%d", right);
pDC->TextOutW(0, 130, L"Right: " + r, _tcslen(r)+7);
CString b;
b.Format(L"%d", bottom);
pDC->TextOutW(0, 160, L"Bottom: " + b, _tcslen(b)+8);
CString t;
t.Format(L"%d", top);
pDC->TextOutW(0, 190, L"Top: " + t, _tcslen(t)+5);
Am I headed in the right direction?
I was thinking I could find the midpoint of the two or something along those lines....
What else do I need to do?
Also: How would I acquire the x-y coordinates of the corners of my physical display as well?
Use the GetWindowRect function instead of the GetClientRect function.
You also may have a look at the ScreenToClient and the ClientToScreen functions.
Adding something to "Left: " is invalid. Use the Format statement to build the entire string to be displayed, and use the CString::GetLength() method if you need the length. (There is a version of TextOut that accepts a CString without the length parameter.)
Related
Context
I try to draw pie chart for statistic in my game. I'm using Cocos2d-x ver.3.8.1. Size of the game is important, so I won't to use third-party frameworks to create pie charts.
Problem
I could not find any suitable method in Cocos2d-x for drawing part of the circle.
I tried to do
I tried to find a solution to this problem in Internet, but without success.
As is known, sector of a circle = triangle + segment. So, I tried to use the method drawSegment() from DrawNode also.
Although it has parameter radius ("The segment radius" written in API reference), radius affects only the thickness of the line.
drawSegment() method draw a simple line, the thickness of which is set by a method call.
Question
Please prompt me, how can I draw a segment or a sector of a circle in Cocos2d-x?
Any advice will be appreciated, thanks.
I think the one of the ways to draw a sector of a circle in Cocos2d-X is the way to use drawPolygon on DrawNode. I wrote little sample.
void drawSector(cocos2d::DrawNode* node, cocos2d::Vec2 origin, float radius, float angle_degree,
cocos2d::Color4F fillColor, float borderWidth, cocos2d::Color4F bordercolor,
unsigned int num_of_points = 100)
{
if (!node)
{
return;
}
const cocos2d::Vec2 start = origin + cocos2d::Vec2{radius, 0};
const auto angle_step = 2 * M_PI * angle_degree / 360.f / num_of_points;
std::vector<cocos2d::Point> circle;
circle.emplace_back(origin);
for (int i = 0; i <= num_of_points; i++)
{
auto rads = angle_step * i;
auto x = origin.x + radius * cosf(rads);
auto y = origin.y + radius * sinf(rads);
circle.emplace_back(x, y);
}
node->drawPolygon(circle.data(), circle.size(), fillColor, borderWidth, bordercolor);
}
This is the function to calculate the position of edge point of circle and draw polygon. If you want to use it, you need to call like following,
auto canvas = DrawNode::create();
drawSector(canvas, cocos2d::Vec2(400, 400), 100, 60, cocos2d::Color4F::GREEN, 2, cocos2d::Color4F::BLUE, 100);
this->addChild(triangle);
The result would be like this. I think the code will help your problem.
I have a group box where I placed a CListCtrl with a custom height
m_FeatureList.GetClientRect(&rect);
nColInterval = rect.Width()/2;
m_FeatureList.InsertColumn(0, _T("ID"), LVCFMT_LEFT, nColInterval);
m_FeatureList.InsertColumn(1, _T("Class"), LVCFMT_RIGHT, nColInterval);
m_FeatureList.ModifyStyle( LVS_OWNERDRAWFIXED, 0, 0 );
m_FeatureList.SetExtendedStyle(m_CoilList.GetExtendedStyle() | LVS_EX_GRIDLINES);
...
int a, b;
m_FeatureList.GetItemSpacing(true, &a, &b);
// data is a vector containing item text
m_FeatureList.MoveWindow(listRect.left, listRect.top, listRect.Width(), b*data.size()+4);
int i = 0;
std::for_each(data.begin(), data.end(), [&](CString& p) { AddDefectListItem(i++,p); });
Now I want to place a picture control below the CListCtrl, but all the functions with CRect confuse me. All them place the control somewhere but not where I want.
//m_FeatureList.GetClientRect(&listRect);
//m_FeatureList.ClientToScreen(&listRect);
m_FeatureList.ScreenToClient(&listRect);
// Oh my god, which coordinates do I need???
m_image.MoveWindow(listRect.left, listRect.bottom+3,listRect.Width(), 20);
Can somebody help me with this crazy mfc stuff?
The left and top members returned by GetClientRect are always zero. So calling m_FeatureList.GetClientRect tells you nothing about where the control is located. You have to call m_FeatureList.GetWindowRect and then convert the result to get its position relative to the parent dialog.
CRect listRect;
m_FeatureList.GetWindowRect(&listRect);
ScreenToClient(&listRect);
listRect.top = listRect.bottom +3;
listRect.bottom = listRect.top + 20;
m_image.MoveWindow(&listRect);
I'm using QPainter to draw multiline text on QImage. However, I also need to display a colored rectangle around each character's bounding box.
So I need to know the bounding box that each character had when being drawn.
For example, for
painter.drawText(QRect(100, 100, 200, 200), Qt::TextWordWrap, "line\nline2", &r);
I would need to get 10 rectangles, taking into account newlines, word-wrap, tabs, etc.
For example, the rectangle of the second 'l' would be below the rectangle of the first 'l', instead of being to the right of 'e', because of the newline.
Something like the coordinates of the red rectangles in this picture (I've put them by hand so they're not really the correct positions):
This may not be the best solution, but it's the best one I can think of.
I believe you will have to "do it yourself". That is, instead of drawing a block of text, draw each character one at a time. Then you can use QFontMetrics to get the bounding box of each character.
It's a little work, but not too bad. Something like (pseudo code, not code):
QFontMetrics fm(myFont, paintDevice);
int x = startX;
int y = startY;
for (unsigned int i = 0; i < numChars; i++)
{
char myChar = mystr[i]; // get character to print/bound
QRect rect = fm.boundingRect( myChar ); // get that char's bounding box
painter.drawText(x, y, Qt::TextWordWrap, mystr[i], &r); // output char
painter.drawRect(...); // draw char's bounding box using 'rect'
x += rect.width(); // advance current position horizontally
// TODO:
// if y > lineLen // handle cr
// x = startX;
// y += line height
}
Check out QFontMetrics, it has a number of different methods for getting bounding boxes, minimum bounding boxes, etc.
QFontMetrics 4.7
Ahhh... I see now that the overload you're using returns the actual bounding rect. You can just use that and skip the QFontMetrics if you like - otherwise the overall algorithm is the same.
You can retrieve the bounding boxes of individual characters with QFontMetrics::boundingRect(QChar), but they have to be rendered at an offset (QFontMetrics::ascent from the top as well as QFontMetrics::width of the preceding characters from the left) because they are relative to the font’s base line and not to the bottom of the bounding box of the complete string.
Several lines also have to be handled separately.
QFontMetrics::lineSpacing give you their offset.
QPainter painter(this);
painter.setFont(QFont("Arial", 72));
auto pen = painter.pen();
QString text{"line\nline2\ngg\n`"};
QRect boundingRect;
painter.drawText(rect(), Qt::AlignLeft | Qt::AlignTop, text, &boundingRect);
painter.drawRect(boundingRect.adjusted(0, 0, -pen.width(), -pen.width()));
pen.setColor(Qt::red);
painter.setPen(pen);
const auto lines = text.split('\n');
const auto fm = painter.fontMetrics();
for (int linei = 0; linei < lines.size(); ++linei) {
const auto & line = lines[linei];
for (int chi = 0; chi < line.size(); ++chi) {
const auto bounds = fm.boundingRect(line[chi]);
const auto xoffset = bounds.x() + fm.width(line, chi);
const auto lineOffset = linei * fm.lineSpacing() + fm.ascent();
const auto yoffset = lineOffset + bounds.y();
painter.drawRect(QRect{xoffset, yoffset, bounds.width(), bounds.height()});
}
}
results in
which, sadly – isn’t perfect though.
I want to draw multiple filled ellipses on/in some panel. Drawing single one isnt problem, i am using:
Color aColor = Color::FromArgb( 255, 0, 0 );
SolidBrush^ aBrush = gcnew SolidBrush(aColor);
Rectangle rect = Rectangle(x, y, 10, 10);
e->Graphics->FillEllipse(aBrush, rect);
It draws red ellipse bordered by rectangle, and fills it with red color. (assuming i will give x and y). The problem i met, is when I want to draw multiple ellipses like that, in RANDOM places. So i need to pass random x and y (using rand() % somenumber) but i am not sure, how can i pass these variables into the panel1_paint function and draw them when both numbers are randomized. Also, ofc i dont want the last ellipse to disappear when drawing new one. The only way is using global variables?
Any ideas?
Well, i tried as suggested, to use loop inside panel and i got that:
for(int i=0; i<ile_przeszkod; i++){
int x = rand() % 690; int y = rand() % 690;
Color aColor = Color::FromArgb( 255, 0, 0 );
SolidBrush^ aBrush = gcnew SolidBrush(aColor);
Rectangle rect = Rectangle(x, y, 10, 10);
e->Graphics->FillEllipse(aBrush, rect);
MessageBox::Show("x: "+x+ " y: " +y);
}
ile_przeszkod means how many of them i want to be drawn, and message box showes me what numbers it randomized so i am sure ellipses dont overlap. The problem is, after "invalidating" panel1 i see only 1 ellipse. :/ What should i do to see both of them?
all the x, y coordinates are random , so they don't depend on some other deciding procedure, So that need not to be passed to panel1_paint rather you can run a lpop and generate random number to use them as your x, y coordinates.
is there a way to use mouse as an event handler in c/c++ im making a game on snakes and ladder (the famous board game) and trying to make it with basic borland c++ compiler working with a header file called graphics.h, which is very basic and gives output of 640 X 480 res, so I was wondering if there is a possiblity of using mouse as an event handler (about which i have no experiance)to have control over the palyer coins on the board.
I'm not sure which version of graphics.h you happen to have, but there are functions getmousey, getmousey, clearmouseclick and getmouseclick. See this for some documentation that may work for you.
It appeas that you can use registermousehandler and a call-back function to do some level of event-based programming. Here's a sample from the document I sent you.
// The click_handler will be called whenever the left mouse button is
// clicked. It checks copies the x,y coordinates of the click to
// see if the click was on a red pixel. If so, then the boolean
// variable red_clicked is set to true. Note that in general
// all handlers should be quick. If they need to do more than a little
// work, they should set a variable that will trigger the work going,
// and then return.
bool red_clicked = false;
void click_handler(int x, int y)
{
if (getpixel(x,y) == RED)
red_clicked = true;
}
// Call this function to draw an isosoles triangle with the given base and
// height. The triangle will be drawn just above the botton of the screen.
void triangle(int base, int height)
{
int maxx = getmaxx( );
int maxy = getmaxy( );
line(maxx/2 - base/2, maxy - 10, maxx/2 + base/2, maxy - 10);
line(maxx/2 - base/2, maxy - 10, maxx/2, maxy - 10 - height);
line(maxx/2 + base/2, maxy - 10, maxx/2, maxy - 10 - height);
}
void main(void)
{
int maxx, maxy; // Maximum x and y pixel coordinates
int divisor; // Divisor for the length of a triangle side
// Put the machine into graphics mode and get the maximum coordinates:
initwindow(450, 300);
maxx = getmaxx( );
maxy = getmaxy( );
// Register the function that handles a left mouse click
registermousehandler(WM_LBUTTONDOWN, click_handler);
// Draw a white circle with red inside and a radius of 50 pixels:
setfillstyle(SOLID_FILL, RED);
setcolor(WHITE);
fillellipse(maxx/2, maxy/2, 50, 50);
// Print a message and wait for a red pixel to be double clicked:
settextstyle(DEFAULT_FONT, HORIZ_DIR, 2);
outtextxy(20, 20, "Left click in RED to end.");
setcolor(BLUE);
red_clicked = false;
divisor = 2;
while (!red_clicked)
{
triangle(maxx/divisor, maxy/divisor);
delay(500);
divisor++;
}
cout << "The mouse was clicked at: ";
cout << "x=" << mousex( );
cout << " y=" << mousey( ) << endl;
// Switch back to text mode:
closegraph( );
}
You can use Mouse and Keyboard events using Win32 Programming (In Visual Studio).
Is it the requirement to use borland c++.
I think similar APIs are there in borland c++.
You can refer http://www.functionx.com/win32/index.htm for more information on event handling in Visual Studio using Win32 Programming.