Draw rectangle on panel Visual C++ using a paint event - visual-c++

I've painted several rectangles on a panel, using 'CreateGraphics()'. Though they always disappeared after minimizing and restoring the window I used the paint-event in order to restore them and everything works fine, always using 'CreateGraphics().
Sometimes ago Mr. Hans Passant gave me the advice to SUBSTITUTE 'CreateGraphics()' with the paint event of the panel. It seems to me, that the 'paint' event is also used for creating, and not only 4 restoring.
Visual C++ DrawRectangle filled:
... In general, do not use CreateGraphics(), whatever you draw won't survive. Minimize and restore your window for example. Use the panel's Paint event instead. – Hans Passant Jul 3 at 12:47
I tried so, but I didn't succeed. I always needed 'CreateGraphics' in order to initialize a pointer to the class 'Graphics' and to use the method 'drawRectangle':
System::Drawing::Graphics ^drawPointer = CreateGraphics();
After that You create the rectangle with
drawPointer->drawRectangle(...);
But going into the 'paint-event' of the panel, how do I reach the method 'drawRectangle' without using 'CreateGraphics()'? Or did I get the advice in the wrong way?

I don't know if I get you right, but usually you get a painting capability like this:
System::Void Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {
System::Drawing::Graphics^ g = e->Graphics;
g->DrawRectangle(...);
}

Related

Are InputComponents and Dialogs incompatible?

In the simple Dialog below:
// choice of layout has no impact:
Container cont=new Container(new TextModeLayout(3, 1));
//Container cont=new Container(new BoxLayout(BoxLayout.Y_AXIS));
TextComponent firstName=new TextComponent().label("First Name").text(person.firstname);
TextComponent lastName=new TextComponent().label("Last Name").text(person.lastname);
TextComponent cost=new TextComponent().label("Cost per Session").text(person.getCostString());
cost.getField().setConstraint(TextArea.DECIMAL);
// NOTE HERE
// doesn't work: // works:
cont.add(firstName); // cont.add(firstName.getField());
cont.add(lastName); // cont.add(lastName.getField());
cont.add(cost); // cont.add(cost.getField());
Dialog.show("Edit Client", cont, new Command(CANCEL), new Command(OK));
Nothing appears in the Dialog unless I add the TextField instead of the TextComponent to my container at the NOTE HERE comment. This means I lose the nice appearance of the labelled input fields (yes I know I could label them myself, but they wouldn't look as good on different devices). My choice of layout manager at the top does not affect this issue (I've tried several). I can't find evidence online to conclude there's an incompatibility here, adding TextComponents and other InputComponents works fine on a Form, just not in a Dialog.
I'm having the same problem in another Dialog that uses PickerComponents. The PickerComponent doesn't appear unless I add the Picker itself, and then the Picker spawned from a Dialog looks all wrong. I'm hoping the simpler code question above will answer this quandary as well.
It's worth noting I've made no theme changes and this problem is noted in both the Android and Apple skins as well as on an actual Android phone. Thanks in advance for any help!
You shouldn't do input in a Dialog as it creates a very problematic user experience. If you would like things to look like they are in a dialog you can use styles and layouts to make a Form feel like a Dialog but you shouldn't use a Dialog.
The reason this fails is a bit complicated but here are the high level problems with using a dialog:
Dialogs don't grow implicitly - This is a huge problem for text input as the component needs space to resize with input and even more so for the animated TextComponent which needs to shift things around. The size of a Dialog is determined when it's shown and that's a big problem
This becomes a bigger problem on Android where the screen resizes during input and distorts the dialog completely. It's one of those things you'll only see on the device because it's really hard to simulate the virtual keyboard.
Scrollability is hard in a Dialog and text components need a scrollable parent so you can scroll between the various edit components
Picker component uses a form of Dialog to show input and this can collide with your dialog
Dialogs are hard to get right for suspend/resume behavior. Suspend/resume happens when the app is minimized or sent to the background. E.g. say you have an incoming call while typing in the dialog. When you go back to the app we want to show the last form. If we show the dialog it will block and we won't know which parent form to show anyway. So when an app is suspended dialogs are just disposed in the default code generated in the main class. It makes more sense.

WM_PAINT not send when using WS_EX_COMPOSITE

I'm working in a legacy application using MFC.
We have a mechanism to enable/disable controls depending on some business logic.
This mechanism is implemented in the CView-derived class. The way it works is all the views in the application derived from a common CView-derived class (CBaseView) and on the PreTranslateMessage all controls of the view are enabled/disabled.
This worked fine so far because all controls send at least WM_PAINT message when they need to be painted. So the system worked without the user having to move the mouse or anything. I recently added some drawing features and I had to use WS_EX_COMPOSITE to get ride of some flickering. With this flag activated my CView-derived class is not getting any called to PreTranslateMessage when creating the view....so the controls are not disabled until the user moves the mouse over the control.
I understand there is no way to send WM_PAINT using WS_EX_COMPOSITE but is there other message I can use to get the same behaviour???
Edited:
I am currently using the OnIdle approach but it has a big drawback, the windows doesn't become idle until after drawing all the controls...so when you enter the screen al controls are enabled and inmediately they are disabled...this makes a quite ugly effect!
More solutions???
Thanks in advance...
The logical place to enable/disable controls would be CView::OnUpdate, it is called by the framework after the view's document has been modified and from OnInitialUpdate(); you can also call this function if there is some change that would trigger re-evaluation of your business logic.
EDIT
After reading the question a bit more closely, what you could also do is to post a private message at the end of OnInitialUpdate and "catch" it in your PreTranslateMessage:
PostMessage(WM_APP, 0, 0);
Calling InvalidateRect followed by UpdateWindow against the window in question will mark the entire client area as dirty and force an immediate repaint. Remember that WM_PAINT is not really a message, in the queue in the usual sense, it is pushed out after all other messages have been processed for that window, which would include any invalidations of the area being drawn. No message is generated at all if there are no invalid segments of the active window display.

Resizable MKOverlay using MKOverlayRenderer

I want to have a custom MKOverlay that's a circle anchored to the user location annotation that the user can resize by pinching. I was able to successfully achieve this using MKOverlayPathRenderer and a custom MKOverlay object by overriding the createPath method and making an arc. The resizing and moving of the overlay was handled by using KVO on the radius and coordinate properties of my overlay. However the resizing was incredibly choppy and the boundingMapRect wasn't correctly calculated.
I've also tried using an image and instead of subclassing MKOverlayPathRenderer just MKOverlayRenderer, overriding - (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context but when I resize my CPU percentage jumps to 160% usage (not great yeah?) and the boundingRect is again being drawn incorrectly.
I really think the way to do it is with MKOverlayPathRenderer and maybe having an atomic counter of some kind so that a redraw only gets called say every 5 or 10 times the pinch gesture is triggered.
Does anyone have any suggestions? I've also considered but haven't tried making a UIView and adding it as a subview to the map view and putting the pinch gesture on that but that seems hacky and dirty.
When you computed new boundingMapRect on the Overlay, you must invoke invalidatePath on your Renderer. After that, system will invoke createPath for you when appropriate.

Using GDI+ to draw tooltip

I'm new to GDI+ programming and am looking for some advice.
I am loading an image from a file and displaying it using the following functions (some pseudo code included):
Gdiplus::Image *i = new Gdiplus::Image(file, other parameters ... );
Gdiplus::DrawImage(i, other parameters ... );
I would like to associate a tooltip with the image. Is there any way that I can automatically set/attach a tooltip to the Gdiplus::Image objact (or any other Gdiplus control that I wish to draw for that matter)?
If not, how can such functionality be achieved? I have looked at CToolTipCtrl in WTL but don't know how to attach it to the Gdiplus::Image.
Thanks in advance.
After investigating this more, I've realised that this is not possible, so to speak. You must use GDI+ to draw your own tool tip my monitoring mouse events to see when it is hovering over something, then using the device context to do the drawing withing the mouse hover event handler.

How do I stop a System::Windows::Forms::UserControl from erasing it's background?

I have a C++/CLI System::Windows::Forms::UserControl derived control which should only redraw (a small portion of) itself as new data is fed into it. For some reason though, the OnPaint mechanism is being called even when there's nothing to cause it external to the app.
Here's a snippet:
void Spectrogram::OnPaint(System::Windows::Forms::PaintEventArgs ^e)
{
// Overidden to stop the background being painted(?)
}
void Spectrogram::AddNewFFTData( float* data, int fataWidth )
{
Graphics^ gfx = CreateGraphics();
//now do some drawing
gfx->Dispose();
}
So I call the add data method to add some new data which should in theory write over the previous entry (which clears some highlighting) and write the new entry.
Back in the day I used to develop MFC/OpenGL apps and one of the first things I'd do would be to override the OnEraseBackground method. As far as I can see though, there's no obvious way of stopping it being erased. What have I missed?
You may be looking for Control.OnPaintBackground(). I've had to override that to do nothing for a custom control I wrote to bring a legacy MFC control into a Winforms project. Otherwise it would paint the background on top of the MFC control's paint job.
Essentially, in the .cpp:
void MyControl::OnPaintBackground(System::Windows::Forms::PaintEventArgs ^pevent)
{
// Do nothing, we don't want to paint over the native control.
// You may want to do something a little fancier for DesignMode
// if you use the winforms designer, though.
}
On the prototype:
protected:
void virtual OnPaintBackground(System::Windows::Forms::PaintEventArgs ^pevent) override;
What rectangle is being passed in to you via the event args? Is the entire control being invalidated, or just a portion of it?
Maybe it's a statement like this in the Form's constructor:
//do own background painting
this.SetStyle(ControlStyles.Opaque, true);
I think that prevents OnPaintBackground being invoked at all: so you don't need to override OnPaintBackground, and instead you can erase the background (or not) yourself in your OnPaint.
I did some stuff with the OnPaint lately (C#, if that matters), and I noticed it literally is drawn when a area of the control is revealed.
A better solution is to draw on a cached Bitmap, and draw it to the control every time dotNet asks for it.

Resources