How to draw GTK stock image inside DrawingArea - c#

I'm writig a simple file browser in GTK#. I want to draw a stock image of a directory inside DrawingArea. I don't want to load external image. I came up to use Gdk.PixBuf but can't figure out how to load stock images.

There are a few ways of doing that, but I believe gtk_icon_theme_load_icon() is the one that is not deprecated and is compatible with most GTK+ versions. You will need a icon GtkIconTheme as a parameter, but in most cases gtk_icon_theme_get_default() is what you want. The icon name parameter is from Icon naming spec.

Ok, so rendering stock items inside DrawingArea is a bit ricky.
private Gdk.GC gc;
private Gdk.Pixbuf pixbuf;
public MainWindow (): base (Gtk.WindowType.Toplevel)
{
Build ();
this.gc = new Gdk.GC((Gdk.Drawable)this.browserArea.GdkWindow);
//the method below does the trick. It is the only method I found that will return
//a valid pixbuf, so you can easily draw with the "usual" DrawPixbuf method in the
//ExposeEvent
this.pixbuf = RenderIcon(Gtk.Stock.Cdrom, IconSize.Dialog, "");
this.browserArea.ExposeEvent += new ExposeEventHandler(OnExposeEvent);
}
protected void OnExposeEvent(object sender, ExposeEventArgs args){
this.browserArea.GdkWindow.DrawPixbuf(this.gc, this.pixbuf,0,0,20,20,-1,-1,Gdk.RgbDither.None,0,0);
}

Related

Getting an image from a GMap.NET.GMapControl without it being visible

I would like to get a map from an online source (whether than be Google Maps, OpenStreetMap, or other) and be able to (1) display it on a form, and (2) save it as an image. These two functions are separate.
After a bit of research I concluded that the GMap.NET.GMapControl was probably the best way of doing this and I implemented this method. However, I have hit a snag when trying to save the image.
I am saving the image by generating a jpeg from the control using its ToImage() method. This works, but only when the map is visible on screen. In my application I need to be able to generate the image without rendering it to screen.
If the GMapControl is not visible, the jpeg is just a black rectangle. The test code below demonstrates this. The form contains two GMapControl controls. If both are visible I get two identical jpeg images. If one is hidden, the corresponding jpeg is blank.
Is there a way I can get the map image using a GMapControl without plotting it to screen? Or should I take a different approach and use something else? The more lightweight the better as far as I am concerned.
(My first attempt was using the WebBrowser control. I moved on from this because I was getting all the borders etc. as well as the map. I tried to exclude everything but the div containing the map, but then I lost everything ; I suspect this may have been because the map div was nested and I was hiding its parent...)
public partial class testForm : Form
{
public testForm()
{
InitializeComponent();
}
private void testForm_Shown(Object sender, EventArgs e)
{
gMapControl2.Hide(); // this results in a blank jpg image for gMapControl2
// Plot the same map to both gMapControls...
PlotMap(gMapControl1);
PlotMap(gMapControl2);
// Excuse the clunky wait method here ; it was due to a 'cross-thread' error when using the event raised by the gMapControl
// It serves the purpose here.
Task.Factory.StartNew(() => { Task.Delay(5000).Wait(); }).Wait(); // wait for 5 seconds to give maps plenty of time to render
WriteBitmap(gMapControl1, $#"E:\Test_gMapControl1.jpg");
WriteBitmap(gMapControl2, $#"E:\Test_gMapControl2.jpg");
}
private void PlotMap(GMapControl gMapControl)
{
gMapControl.MapProvider = GoogleMapProvider.Instance;
GMaps.Instance.Mode = AccessMode.ServerOnly;
gMapControl.ShowCenter = false;
gMapControl.MinZoom = 1;
gMapControl.MaxZoom = 25;
gMapControl.Zoom = 10;
gMapControl.Position = new PointLatLng(10, 10); // centered on 10 lat, 10 long
}
private void WriteBitmap(GMapControl gMapControl, string filename)
{
Image b = gMapControl.ToImage();
b.Save(filename, ImageFormat.Jpeg);
}
}

Custom WinForms button does not change image?

I created a custom Button, called AcceptButton, inheriting from System.Windows.Forms.Button
On the constructor I set a few properties, but most important, an image (A green checkmark), like this:
this.Image = Proyecto.Controls.Bases.Properties.Resources.ok_16;
When I add this control using VS2013 form designer, in another project that references the DLL I just created, the image is displayed correctly. But if I go into my control, and change the image in code, for example, to:
this.Image = Proyecto.Controls.Bases.Properties.Resources.ok_32;
The image is not changed in the projects that use this control (even if the solution is cleaned and regenerated). I followed the code generated by VS2013 and I found that the designer adds this line:
this.botonAceptar1.Image = ((System.Drawing.Image)(resources.GetObject("botonAceptar1.Image")));
For some reason, this resource is "hardcoded" in a resource file generated by VS, but it's not updated when I regenerate the solution.
Removing this line makes it work as expected (I can change the image in the "upstream" class and it'll be updated when the solution is regenerated).
Why is this happening?
How can I avoid this?
This happens due to the DesignerSerializationVisibility (MSDN) attribute. Try adding this property and these methods (MSDN) to your class:
public class MyButton : System.Windows.Forms.Button
{
public bool ShouldSerializeImage()
{
return !object.ReferenceEquals(this.Image, _BaseImage);
}
public void ResetImage()
{
this.Image = _BaseImage;
}
[System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Visible)]
public new Image Image
{
get { return base.Image; }
set { base.Image = value; }
}
private Bitmap _BaseImage;
public MyButton()
{
_BaseImage = Proyecto.Controls.Bases.Properties.Resources.ok_16;
this.Image = _BaseImage;
}
}
This replaces the default Image property and prevents the serialization you encountered. Furthermore it allows the designer to check if the property has it's default value and if it needs to be serialized. The default value is stored in a private field in the button class. This should correctly serialize (or not serialize) the properties.
Remove all buttons you have, recompile, readd the buttons to make sure.

Draw adornments on windows.forms.controls in Visual Studio Designer from an extension

I wrote an Visual Studio 2013 extension that observes Windows.Forms designer windows. When a developer is changing controls in the designer window, the extension tries to verify that the result is consistent with our ui style guidelines. If possible violations are found they are listed in a tool window. This all works fine.
But now I would like to mark the inconsistent controls in the designer window, for example with a red frame or something like this.
Unfortunately, I did not find a way to draw adornments on controls in a designer window. I know that you can draw those adornments if you develop your own ControlDesigner, but I need to do it from "outside" the control's designer. I only have the IDesignerHost from the Dte2.ActiveWindow and can access the Controls and ControlDesigners via that host. I could not find any way to add adornments from "outside" the ControlDesigners.
My workaround for now is to catch the Paint-Events of the controls and try to draw my adornments from there. This doesn't work well for all controls (i.e. ComboBoxes etc), because not all controls let you draw on them. So I had to use their parent control's Paint event. And there are other drawbacks to this solution.
I hope someone can tell me if there is a better way. I'm pretty sure that there has to be one: If you use Menu->View->Tab Order (not sure about the correct english menu title, I'm using a german IDE), you can see that the IDE itself is able to adorn controls (no screenshot because it's my first post on SO), and I'm sure it is not using a work around like me. How does it do that?
I've been googling that for weeks now. Thanks for any help, advice, research starting points....
UPDATE:
Maybe it gets a little bit clearer with this screenshot:
Those blue numbered carets is what Visual Studio shows when selecting Tab order from the View menu. And my question is how this is done by the IDE.
As mentioned I tried to do it in the Paint event of the controls, but e.g. ComboBox doesn't actually support that event. And if I use the parent's Paint event I can only draw "around" the child controls because they are painted after the parent.
I also thought about using reflection on the controls or the ControlDesigners, but am not sure how to hook on the protected OnPaintAdornments method. And I don't think the IDE developers used those "dirty" tricks.
I believe you are seeking for BehaviorService architecture. The architecture with supporting parts like Behavior, Adorner and Glyph and some examples is explained here Behavior Service Overview. For instance
Extending the Design-Time User Interface
The BehaviorService model enables new functionality to be easily layered on an existing designer user interface. New UI remains independent of other previously defined Glyph and Behavior objects. For example, the smart tags on some controls are accessed by a Glyph in the upper-right-hand corner of the control (Smart Tag Glyph).
The smart tag code creates its own Adorner layer and adds Glyph objects to this layer. This keeps the smart tag Glyph objects separate from the selection Glyph objects. The necessary code for adding a new Adorner to the Adorners collection is straightforward.
etc.
Hope that helps.
I finally had the time to implement my solution and want to show it for completeness.
Of course I reduced the code to show only the relevant parts.
1. Obtaining the BehaviorService
This is one of the reasons why I don't like the service locator (anti) pattern. Though reading a lot of articles, I didn't came to my mind that I can obtain a BehaviorService from my IDesignerHost.
I now have something like this data class:
public class DesignerIssuesModel
{
private readonly BehaviorService m_BehaviorService;
private readonly Adorner m_Adorner = new Adorner();
private readonly Dictionary<Control, MyGlyph> m_Glyphs = new Dictionary<Control, MyGlyph>();
public IDesignerHost DesignerHost { get; private set; }
public DesignerIssuesModel(IDesignerHost designerHost)
{
DesignerHost = designerHost;
m_BehaviorService = (BehaviorService)DesignerHost.RootComponent.Site.GetService(typeof(BehaviorService));
m_BehaviorService.Adornders.Add(m_Adorner);
}
public void AddIssue(Control control)
{
if (!m_Glyphs.ContainsKey(control))
{
MyGlyph g = new MyGlyph(m_BehaviorService, control);
m_Glyphs[control] = g;
m_Adorner.Glyphs.Add(g);
}
m_Glyphs[control].Issues += 1;
}
public void RemoveIssue(Control control)
{
if (!m_Glyphs.ContainsKey(control)) return;
MyGlyph g = m_Glyphs[control];
g.Issues -= 1;
if (g.Issues > 0) return;
m_Glyphs.Remove(control);
m_Adorner.Glyphs.Remove(g);
}
}
So I obtain the BehaviorService from the RootComponent of the IDesignerHost and add a new System.Windows.Forms.Design.Behavior.Adorner to it. Then I can use my AddIssue and RemoveIssue methods to add and modify my glyphs to the Adorner.
2. My Glyph implementation
Here is the implementation of MyGlyph, a class inherited from System.Windows.Forms.Design.Behavior.Glyph:
public class MyGlyph : Glyph
{
private readonly BehaviorService m_BehaviorService;
private readonly Control m_Control;
public int Issues { get; set; }
public Control Control { get { return m_Control; } }
public VolkerIssueGlyph(BehaviorService behaviorService, Control control) : base(new MyBehavior())
{
m_Control = control;
m_BehaviorService = behaviorService;
}
public override Rectangle Bounds
{
get
{
Point p = m_BehaviorService.ControlToAdornerWindow(m_Control);
Graphics g = Graphics.FromHwnd(m_Control.Handle);
SizeF size = g.MeasureString(Issues.ToString(), m_Font);
return new Rectangle(p.X + 1, p.Y + m_Control.Height - (int)size.Height - 2, (int)size.Width + 1, (int)size.Height + 1);
}
}
public override Cursor GetHitTest(Point p)
{
return m_Control.Visible && Bounds.Contains(p) ? Cursors.Cross : null;
}
public override void Paint(PaintEventArgs pe)
{
if (!m_Control.Visible) return;
Point topLeft = m_BehaviorService.ControlToAdornerWindow(m_Control);
using (Pen pen = new Pen(Color.Red, 2))
pe.Graphics.DrawRectangle(pen, topLeft.X, topLeft.Y, m_Control.Width, m_Control.Height);
Rectangle bounds = Bounds;
pe.Graphics.FillRectangle(Brushes.Red, bounds);
pe.Graphics.DrawString(Issues.ToString(), m_Font, Brushes.Black, bounds);
}
}
The details of the overrides can be studied in the links posted in the accepted answer.
I draw a red border around (but inside) the control and add a little rectangle containing the number of found issues.
One thing to note is that I check if Control.Visible is true. So I can avoid to draw the adornment when the control is - for example - on a TabPage that is currently not selected.
3. My Behavior implementation
Since the constructor of the Glyph base class needs an instance of a class inherited from Behavior, I needed to create a new class. This can be left empty, but I used it to show a tooltip when the mouse enters the rectangle showing the number of issues:
public class MyBehavior : Behavior
{
private static readonly ToolTip ToolTip = new ToolTip
{
ToolTipTitle = "UI guide line issues found",
ToolTipIcon = ToolTipIcon.Warning
};
public override bool OnMouseEnter(Glyph g)
{
MyGlyph glyph = (MyGlyph)g;
if (!glyph.Control.Visible) return false;
lock(ToolTip)
ToolTip.Show(GetText(glyph), glyph.Control, glyph.Control.PointToClient(Control.MousePosition), 2000);
return true;
}
public override bool OnMouseLeave(Glyph g)
{
lock (ToolTip)
ToolTip.Hide(((MyGlyph)g).Control);
return true;
}
private static string GetText(MyGlyph glyph)
{
return string.Format("{0} has {1} conflicts!", glyph.Control.Name, glyph.Issues);
}
}
The overrides are called when the mouse enters/leaves the Bounds returned by the MyGlyph implementation.
4. Results
Finally I show screenshot of a example result. Since this was done by the real implementation, the tooltip is a little more advanced. The button is misaligned to all the comboboxes, because it's a little too left:
Thanks again to Ivan Stoev for pointing me to the right solution. I hope I could make clear how I implemented it.
Use the System.Drawing.Graphics.FromHwnd method, passing in the HWND for the designer window.
Get the HWND by drilling down into the window handles for visual studio, via pinvoke. Perhaps use tools like Inspect to find window classes and other information that might help you identify the correct (designer) window.
I've written a C# program to get you started here.

Highlighting a particular control while capturing screenshot of a dialog in web page in c#

I have a requirement to capture the screen shot of the opened dialog with a particular html control highlighted ( whose static id is given ). currently I Implemented the code following manner :
public void Snapshot()
{
Image currentImage = null;
currentImage = GetOpenedDialogFrame().CaptureImage();
}
public UITestControl GetOpenedDialogFrame()
{
var dialogsFrames = new HtmlDiv(this.BrowserMainWindow.UiMobiControlDocument);
dialogsFrames.SearchProperties.Add(new PropertyExpression(HtmlControl.PropertyNames.Class, "mcw-dialog", PropertyExpressionOperator.Contains));
var dialogs = dialogsFrames.FindMatchingControls();
if (dialogs.Count == 0)
{
return null;
}
return dialogs[dialogs.Count - 1];
}
Now I have to write the code to highlight the particular html control while taking a screenshot. The DrawHighlight() method of Microsoft.VisualStudio.TestTools.UITesting.dll does not take any parameter so how can I highlight a particular html control in the screenshot.
DrawHighlight() is a method of a UI Control. It could be used in this style:
public void Snapshot()
{
Image currentImage = null;
var control = GetOpenedDialogFrame();
// TODO: protect the code below against control==null.
control.DrawHighlight();
currentImage = control.CaptureImage();
}
Whilst that answers your question about DrawHighlight, I am not sure it will achieve what you want. Please see this question the Microsoft forums where they are trying to do a similar screen capture.
Why not simply user the playback settings:
Playback.PlaybackSettings.LoggerOverrideState = HtmlLoggerState.AllActionSnapshot;
This will produce the html log file with all the screenshots that your codedui test went threw.
After searching for the matching controls you can try to highlight each one of them.
something like:
foreach( var control in controls)
{
control.drawhighlight();
}
that way you'll be able to which controls are located by the playback(qtagent to be more precise). furthermore this will help you decide which instance to refer to. (run and wait to see which controls are highlighted, pick the one you need and hard code it to be part of the test).
so after the test run you'll end up with something like:
var dialogs = dialogsFrames.FindMatchingControls();
dialogs[desiredLocation].drawhighlight();
hope this helps.

C# syntax to get access to webcontrol in different file (aspx)

Within my Website project, I have some aspx pages, javascript files, and a custom C# class I called MyCustomReport. I placed a Image box with an ID of Image1 inside SelectionReport.aspx. I need to get access to that Image1 inside MyCustomReport.cs so I can turn it on and off based on conditions. What code do I need to do this? Thanks everyone
You'll need to pass the instance of Image control to MyCustomReport. From there you'll be able to set it's Visible property to true or false.
Probably something like this
public partial class SelectionReport : Page
{
// your code here
protected void Page_Load( object sender, EventArgs e ){
MyCustomReport myCustomReport = new MyCustomReport();
myCustomReport.MyReport( Image1 );
}
}
public class MyCustomReport
{
public void MyReport( Image arg ){
// some more code
arg.Visible = false; // or true
}
}
EDIT derek is right, you won't need the entire page, just the image.
it sounds a bit odd to do it that way. You could pass the control to the class method using the ref keyword, then the class could modify it:
doSomething(data, MyUserControl);
I think a better implementation would be for your class to have a method or property that the page could query to turn the control on or off.

Categories