|
Liz,
Geez.. that is a very wide screen that you have! I haven't got the environment to try, but did you try my suggested code in other thread:
====================================================
When it come to adjusting for drawing, I tempt to use the graphic resolution, so say "g" is the Graphics object, I would do something like this:
int iWidth = (int) ((g.DpiX/96.0f) * DROPDOWNWIDTH);
I use 96 there because that is the pixel size for standard font display. I also make it a float so that we keep the precision when performing the math.
====================================================
See if that works for you.
Fadrian
|
|
|
|
|
Fadrian,
I am new to CodeProject.com and am excited to hear from you. Yes I did add this dropdownwidth code snippet from ont of the threads as well as the resize snippet.
I also added the OnResize snippet
Everything compiles well.
I think it may be the videocard on the Sony Vaio stretches things, as I am having troubles with the rest of my form where relative co-ordinates are working out better than absolute co-ordinates. This is interesting, and may become more of an issue for software developers as the panoramic screen resolutions become more common over time.
Elizabeth Gee
Information Architect - .Net Developer
http://www.nwtd.com
|
|
|
|
|
BTW,
I went to the Form level properties and set the AutoScale to False. This did not change the Bug on the control where there is a 3D wide artifact between the textbox and the arrow.
Elizabeth Gee
Information Architect - .Net Developer
http://www.nwtd.com
|
|
|
|
|
Liz,
AutoScale can be nasty and I constantly run into problem with it.
Can you capture the screen of the 3D wide artifact problem and send to my email a/c? Once I see the exact prob, I may be able to make other suggestion.
Fadrian
|
|
|
|
|
Here is a link to a screenshot of your Flat Combo on my Sony Vaio at 16oox1200 resolution:
http://www32.brinkster.com/icontoo/Temp/FlatComboOnSonyVaio.html
Also, here is your code with the two modifications made by others, which I compiled down to a C# DLL as depicted in the screenshot:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
namespace DrawFlat
{
[ToolboxBitmap(typeof(System.Windows.Forms.ComboBox))]
public class FlatComboBox: ComboBox
{
public const int WM_ERASEBKGND = 0x14;
public const int WM_PAINT = 0xF;
public const int WM_NC_PAINT = 0x85;
public const int WM_PRINTCLIENT = 0x318;
[DllImport("user32.dll", EntryPoint="SendMessageA")]
public static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, object lParam);
[DllImport("user32")]
public static extern IntPtr GetWindowDC (IntPtr hWnd );
[DllImport("user32")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC );
public FlatComboBox()
: base()
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
}
protected override void OnSelectedValueChanged(EventArgs e)
{
base.OnSelectedValueChanged (e);
this.Invalidate();
}
protected override void WndProc(ref Message m)
{
if (this.DropDownStyle == ComboBoxStyle.Simple)
{
base.WndProc(ref m);
return;
}
IntPtr hDC = GetWindowDC(this.Handle);
Graphics gdc = Graphics.FromHdc(hDC);
switch (m.Msg)
{
case WM_NC_PAINT:
SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
SendPrintClientMsg(); // send to draw client area
PaintFlatControlBorder(this, gdc);
m.Result = (IntPtr) 1; // indicate msg has been processed
break;
case WM_PAINT:
base.WndProc(ref m);
// flatten the border area again
Pen p = new Pen((this.Enabled? BackColor:SystemColors.Control), 2);
gdc.DrawRectangle(p, new Rectangle(2, 2, this.Width-3, this.Height-3));
PaintFlatDropDown(this, gdc);
PaintFlatControlBorder(this, gdc);
break;
default:
base.WndProc(ref m);
break;
}
ReleaseDC(m.HWnd, hDC);
gdc.Dispose();
}
private void SendPrintClientMsg()
{
// We send this message for the control to redraw the client area
Graphics gClient = this.CreateGraphics();
IntPtr ptrClientDC = gClient.GetHdc();
SendMessage(this.Handle, WM_PRINTCLIENT, ptrClientDC, 0);
gClient.ReleaseHdc(ptrClientDC);
gClient.Dispose();
}
private void PaintFlatControlBorder(Control ctrl, Graphics g)
{
Rectangle rect = new Rectangle(0, 0, ctrl.Width, ctrl.Height);
if (ctrl.Focused == false || ctrl.Enabled == false )
ControlPaint.DrawBorder(g, rect, SystemColors.ControlDark, ButtonBorderStyle.Solid);
else
ControlPaint.DrawBorder(g, rect, Color.Black, ButtonBorderStyle.Solid);
}
public static void PaintFlatDropDown(Control ctrl, Graphics g)
{
const int DROPDOWNWIDTH = 18;
int iWidth = (int) ((g.DpiX/96.0f) * DROPDOWNWIDTH);
//Rectangle rect = new Rectangle(ctrl.Width-DROPDOWNWIDTH, 0, DROPDOWNWIDTH, ctrl.Height);
Rectangle rect = new Rectangle(ctrl.Width-iWidth, 0, iWidth, ctrl.Height);
ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);
}
protected override void OnLostFocus(System.EventArgs e)
{
base.OnLostFocus(e);
this.Invalidate();
}
protected override void OnGotFocus(System.EventArgs e)
{
base.OnGotFocus(e);
this.Invalidate();
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Invalidate();
}
}
}
Elizabeth Gee
Information Architect - .Net Developer
http://www.nwtd.com
|
|
|
|
|
Liz,
Looks like the width of the dropdown combo is 1 pixel out. I would just change the DROPDOWNWIDTH to 19. It doesn't really matter in normal screen display for the dropdown combo to be 1 pixel wider. Perhaps 19 would be a better size to be used as it will cover the standard 17 pixel width combo and total of 2 3D pixels outer border for the left and right.
Fadrian
|
|
|
|
|
Beautiful!
I changed the DROPDOWNWIDTH from 18 to 20 then tho 21, and 21 closed it up perfectly at 1900x1200 resolution
Thanks!
Elizabeth Gee
Information Architect - .Net Developer
http://www.nwtd.com
|
|
|
|
|
Glad to hear. Hmm... the solution may only work with high res display, and may not view nicely in low res display. I still suspect the problem lies with the AutoScale setting and the font used, but don't take my word for that. I yet to find a programatic way to solve this problem. If anyone knows the answer, I will appreciate your feedback.
|
|
|
|
|
Solved: (Fairly much so)
I tested this on my Sony Vaio at:1920x1200, 1600x1200, and 1280x1024. At the higher two resolutions the below fix works great.
Also on my standard Dell desktop machine at 1280x1024, it works great.
I added a check to your code to check for the Screen Resolution width, and it adjusts the DROPDOWNWIDTH for the resolution above or below 1500.
I compiled this C# into a DLL and then tested it on both machines.
What I ran into was the Sony Vaio does a software screen resolution change, not a hardware one, thus when I set the Sony Vaio to 1280x1024, get that small vertical artifact between the textbox and the arrow parts of the combo box.
All the rest of the code I left the same as the last time I posted it on this thread. I included the VB.Net and C#.Net variations of this code snippet below...
[Visual Basic.Net]
Public Sub PaintFlatDropDown(ByVal ctrl As Control, ByVal g As Graphics)
Dim DROPDOWNWIDTH As Integer
Dim scrRes As Screen
Dim intScrWidth As Integer
intScrWidth = scrRes.PrimaryScreen.Bounds.Width
If (intScrWidth < 1500) Then
DROPDOWNWIDTH = 18
Else
DROPDOWNWIDTH = 21
End If
Dim rect As Rectangle = New Rectangle(ctrl.Width - DROPDOWNWIDTH, 0, DROPDOWNWIDTH, ctrl.Height)
ControlPaint.DrawComboButton(g, rect, ButtonState.Flat)
End Sub
[C#.Net]
public static void PaintFlatDropDown(Control ctrl, Graphics g)
{
int DROPDOWNWIDTH = 18;
Screen screen = Screen.PrimaryScreen;
if (screen.Bounds.Width > 1500)
DROPDOWNWIDTH = 21;
int iWidth = (int) ((g.DpiX/96.0f) * DROPDOWNWIDTH);
//Rectangle rect = new Rectangle(ctrl.Width-DROPDOWNWIDTH, 0, DROPDOWNWIDTH, ctrl.Height);
Rectangle rect = new Rectangle(ctrl.Width-iWidth, 0, iWidth, ctrl.Height);
ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);
}
Elizabeth Gee
Information Architect - .Net Developer
http://www.nwtd.com
|
|
|
|
|
Hi Elizabeth,
You could also try the snippet:
[C# .NET]
public static void PaintFlatDropDown(Control ctrl, Graphics g)
{
Rectangle rect = new Rectangle(ctrl.Width-SystemInformation.VerticalScrollBarWidth, 0, SystemInformation.VerticalScrollBarWidth, ctrl.Height);
ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);
}
It works fine at lower resulutions, and I guess it should also work fine at higher resolutions since it gets the width of the button from the system... you'll also reduce a bit your code.
Best wishes
|
|
|
|
|
Small correction over my own code.
I've just found that my code snippet shows part of the 3D button aswel, but not due to the resolution but due to the OS it's running. On XP it runs perfectlly and it adjusts to the button width, but the 3D presentation of the button on Windows 2000, is a bit different snd it messes up a bit.
To correct this problem and hide the 3D section of the button (Same as your posted image) I did the following extra modification:
[C# .NET]
public static void PaintFlatDropDown(Control ctrl, Graphics g)
{
int myWidth = SystemInformation.VerticalScrollBarWidth;
myWidth += SystemInformation.Border3DSize.Width ;
Rectangle rect = new Rectangle(ctrl.Width-myWidth, 0, myWidth, ctrl.Height);
ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);
}
As you can see I've added the 3D border default width, this hides completelly the button... I've used the variable "myWidth" as you should add a check in order to add the border Width if windows themes are disabled, and if they are enabled we just skip this check.
Best wishes and hope you find it usefull.
And just a question: You're running the control on a Pre-Windows XP, right?
|
|
|
|
|
Hi all,
This maybe a bit late, but I have properly fix this now in the latest version. if you have a chance, give it a try and let me know.
Fadrian
|
|
|
|
|
|
Why you use this const? Is there any way to check width of this 'dropdown button'? I have bigger fonts than normal - and there is small part of normal 3D button
|
|
|
|
|
I used:
int DROPDOWNWIDTH = ctrl.Height-2;
in my situation it helped - work for normal and large fonts.
|
|
|
|
|
Hi,
I haven't tried the approach you suggested, but it is great knowing that it works for you.
When it come to adjusting for drawing, I tempt to use the graphic resolution, so say "g" is the Graphics object, I would do something like this:
int iWidth = (int) ((g.DpiX/96.0f) * DROPDOWNWIDTH);
I use 96 there because that is the pixel size for standard font display. I also make it a float so that we keep the precision when performing the math.
Cheers,
Fadrian
|
|
|
|
|
Hi Fadrian, I am trying to use your Flat combo in VB.net. But I am very confused, can u help me out?
If you can give me any code (as simple as this one). I will be very thankful to u...
KingVikram
|
|
|
|
|
Hi,
All the code logic will be the same, it is just the mapping of C# code to VB.NET flavour. Unfortunately, I don't have any VB.NET class handy for this control, so you may have to write one yourself. Alternatively, you can make this library and used it in your VB.NET project.
Cheers,
Fadrian
|
|
|
|
|
Hi all
Here it is, the basic flavour.
Still there are 3 questions open, as I did not understand quite well the C#-syntax. The code worked fine for me, but still it would be great if you could approve it
Duc_de_Belfort
'Questions: Are the translations correct??
'1. Question:
'if (ctrl.Focused == false || ctrl.Enabled == false )
'translated as:
' If (ctrl.Focused = False Or ctrl.Enabled = False) Then
'2. Question (what the hell is: this.enabled? BackColor: ... ????)
'Pen p = new Pen((this.Enabled? BackColor:SystemColors.Control), 2)
'translated as:
'Dim p As Pen = New Pen(Me.BackColor, 3)
'3. Question
'Public FlatComboBox()
' : base()
' {
' this.SetStyle(ControlStyles.DoubleBuffer, true);
' }
'translated as:
'Public Sub New()
' MyBase.New()
' Me.SetStyle(ControlStyles.DoubleBuffer, True)
'End Sub
Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Runtime.InteropServices
Public Class FlatComboBox
Inherits ComboBox
Public Const WM_ERASEBKGND As Integer = &H14
Public Const WM_PAINT As Integer = &HF
Public Const WM_NC_PAINT As Integer = &H85
Public Const WM_PRINTCLIENT As Integer = &H318
Declare Function SendMessage Lib "user32" Alias _
"SendMessageA" (ByVal hWnd As IntPtr, ByVal wMsg As Long, _
ByVal wParam As IntPtr, ByVal lParam As Object) As Long
Declare Function GetWindowDC Lib "user32" (ByVal hwnd As IntPtr) As IntPtr
Declare Function ReleaseDC Lib "user32" (ByVal hwnd As IntPtr, ByVal hDC As IntPtr) As Long
Public Sub New()
MyBase.New()
Me.SetStyle(ControlStyles.DoubleBuffer, True)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If (Me.DropDownStyle = ComboBoxStyle.Simple) Then
MyBase.WndProc(m)
Else
Dim hdc As IntPtr = GetWindowDC(Me.Handle)
Dim gdc As Graphics = Graphics.FromHdc(hdc)
Select Case m.Msg
Case WM_NC_PAINT
SendMessage(Me.Handle, WM_ERASEBKGND, hdc, 0)
SendPrintClientMsg() ' send to draw client area
PaintFlatControlBorder(Me, gdc)
m.Result = New IntPtr(1) ' indicate msg has been processed
Case WM_PAINT
MyBase.WndProc(m)
' flatten the border area again
Dim p As Pen = New Pen(Me.BackColor, 3)
gdc.DrawRectangle(p, New Rectangle(2, 2, Me.Width - 3, Me.Height - 3))
PaintFlatDropDown(Me, gdc)
PaintFlatControlBorder(Me, gdc)
Case Else
MyBase.WndProc(m)
End Select
ReleaseDC(m.HWnd, hdc)
gdc.Dispose()
End If
End Sub
Private Sub SendPrintClientMsg()
' We send this message for the control to redraw the client area
Dim gClient As Graphics = Me.CreateGraphics()
Dim ptrClientDC As IntPtr = gClient.GetHdc()
SendMessage(Me.Handle, WM_PRINTCLIENT, ptrClientDC, 0)
gClient.ReleaseHdc(ptrClientDC)
gClient.Dispose()
End Sub
Private Sub PaintFlatControlBorder(ByVal ctrl As Control, ByVal g As Graphics)
Dim rect As Rectangle = New Rectangle(0, 0, ctrl.Width, ctrl.Height)
If (ctrl.Focused = False Or ctrl.Enabled = False) Then 'how is || transmitted: & or or?
ControlPaint.DrawBorder(g, rect, SystemColors.ControlDark, ButtonBorderStyle.Solid)
Else
ControlPaint.DrawBorder(g, rect, Color.Black, ButtonBorderStyle.Solid)
End If
End Sub
Public Sub PaintFlatDropDown(ByVal ctrl As Control, ByVal g As Graphics)
Const DROPDOWNWIDTH As Integer = 18
Dim rect As Rectangle = New Rectangle(ctrl.Width - DROPDOWNWIDTH, 0, DROPDOWNWIDTH, ctrl.Height)
ControlPaint.DrawComboButton(g, rect, ButtonState.Flat)
End Sub
Protected Overrides Sub OnSelectedValueChanged(ByVal e As System.EventArgs)
MyBase.OnSelectedValueChanged(e)
Me.Invalidate()
End Sub
Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
MyBase.OnLostFocus(e)
Me.Invalidate()
End Sub
Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)
MyBase.OnGotFocus(e)
Me.Invalidate()
End Sub
Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
MyBase.OnResize(e)
Me.Invalidate()
End Sub
End Class
|
|
|
|
|
Sorry for the late reply.
OK, answer to your questions in order:
1. Correct
2. Conditional Statement. It is like a shorthand to if else statement. You will write in VB as
If (Enabled = True) Then
pen = new Pen(Me.BackColor, 2)
Else
pen = new Pen(SystemColors.Control, 2)
EndIf
3. Correct
I skim through the code and it looks OK
|
|
|
|
|
Hi Fadrian
Thanks for your answer. I c the meaning now.
But let me as vb-guy point out that we (in the vb-world) as well can write the sentence in one line:
Dim p As Pen = New Pen(IIf(Enabled, Me.BackColor, SystemColors.Control), 2)
Cheers,
Duc
PS: Thanks for your contribution again!
|
|
|
|
|
Hi Fadrian
Thanks for your answer. I c the meaning now.
But let me as vb-guy point out that we (in the vb-world) as well can write the sentence in one line:
Dim p As Pen = New Pen(IIf(Me.Enabled, Me.BackColor, SystemColors.Control), 2)
Cheers,
Duc
PS: Thanks for your contribution again!
|
|
|
|
|
Compiling your C# code down to a dll, and importing it into my project as a Reference works fine also, without having to convert it to VB.Net.
Add this to the code:
Imports DrawFlat.FlatComboBox
'then in the vb code change
Me.ComboBox1 = New System.Windows.Forms.ComboBox
'to this:
Me.ComboBox1 = New DrawFlat.FlatComboBox
'works like a charm
Elizabeth Gee
Information Architect - .Net Developer
http://www.nwtd.com
|
|
|
|
|
Liz,
Glad to hear that it works well for you, although I have seen a new bug just being reported by you I will answer that soon.
Fadrian
|
|
|
|
|
Hi Fadrian. I've downloaded your classs and I realized that it doesn't displays correctly when the form is resized. I've made a little change and overrided the OnResize method calling Invalidate():
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Invalidate();
}
Making this change the control resizes correctly.
Ricardo
|
|
|
|
|