I am creating windows Tabbed Application. Everything is good but the tabs are quiet faded and borders are very dull. I have tried changing the border style to 3D as well but no effect. Below is the screenshot
There are forums where people have suggested to use third party library to make Google Chrome type tabs. But I want the native way to get beautiful tabs.
You can take control of how the tabs are drawn by setting the DrawMode = TabDrawMode.OwnerDrawFixed. The example below assumes you have a TabControl named tabControl1 on the form, this will add a new tab with a blue box.
private Rectangle myTabRect;
private Rectangle myInsideRect;
private Rectangle myOutsideRect;
public Form1()
{
InitializeComponent();
TabPage tabPage1 = new TabPage();
// Sets the tabs to be drawn by the parent window Form1.
// OwnerDrawFixed allows access to DrawItem.
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
tabControl1.Controls.Add(tabPage1);
tabControl1.Location = new Point(25, 25);
tabControl1.Size = new Size(250, 250);
tabPage1.TabIndex = 0;
myTabRect = tabControl1.GetTabRect(0);
myInsideRect = new Rectangle(tabControl1.DisplayRectangle.X -1, tabControl1.DisplayRectangle.Y -1, tabControl1.DisplayRectangle.Width + 1, tabControl1.DisplayRectangle.Height + 1);
myOutsideRect = tabControl1.ClientRectangle;
myOutsideRect.Width--;
myOutsideRect.Height--;
ClientSize = new Size(300, 500);
Controls.Add(tabControl1);
tabControl1.DrawItem += new DrawItemEventHandler(OnDrawItem);
}
private void OnDrawItem(object sender, DrawItemEventArgs e)
{
// Draw your tab graphics here
Graphics g = e.Graphics;
Pen p = new Pen(Color.Blue);
g.DrawRectangle(p, myTabRect);
p = new Pen(Color.Red);
g.DrawRectangle(p, myInsideRect);
p = new Pen(Color.Green);
g.DrawRectangle(p, myOutsideRect);
}
You can draw whatever style you like into the graphic context, add text, images, etc
Related
I am working on an Accessibility Screen Reader application that will put a rectangle highlighter around the element that is selected on the Focused program. I am able to detect the currently focused AutomationElement, and get its BoundingRectangle property. (How is Spy++ element highlighting working?)
Given a rectangle's topLeftCorner and bottomRightCorner, I am trying to draw a highlighter rectangle using the code below:
internal class HighlighterForm : Form
{
public HighlighterForm(Point topLeftCorner, Point bottomRightCorner, float borderWidth=5){
int length = bottomRightCorner.X - topLeftCorner.X;
int width = bottomRightCorner.Y - topLeftCorner.Y;
this.Text = "Highlighter";
this.FormBorderStyle = FormBorderStyle.None;
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(topLeftCorner.X, topLeftCorner.Y);
this.TopLevel = true;
this.TopMost = true;
this.Size = new Size(length, width);
// Make the Form background transparent
this.TransparencyKey = Color.Turquoise;
this.BackColor = Color.Turquoise;
this.Paint += (o, e) => {
Graphics g = e.Graphics;
using (Pen selPen = new Pen(Color.Blue, borderWidth*2))
{
g.DrawRectangle(selPen, 0, 0, length, width);
}
};
}
}
And then, I am using the following snippet to create the highlighter:
Point topLeftCorner = new Point(10, 50);
Point bottomRightCorner = new Point(600, 200);
HighlighterForm highlighter = new HighlighterForm(topLeftCorner, bottomRightCorner);
highlighter.ShowDialog();
This can draw a rectangle anywhere on the screen, but the problem is that this form does not let any contents found on an app under the rectangle to be selected. For example, if the currently selected element is a page from Microsoft Word, then the user won't be able to select a paragraph because the rectangle is on top.
How can I make sure the rectangle is there only visually and cannot be interacted with or clicked on?
After seeing that drawing to the desktop is extremely messy, I decided just to research around. I figured out that many people suggest creating a transparent WinForm that is the size of the screen and smacking a panel on there and using that to draw graphics. So I tested it out but ran into many errors. At first, my second form (Form2) wouldn't show, so I had to put it into another thread and put Form2.ShowDialog(); on that thread. After I got that problem out of the way, I actually drew to the panel. Now my form will never show, but I can see it running on my taskbar. Everytime I try to make it the focused window, it never works, and whenever I hover the task I can see the graphics being created. My question is, is it possible to draw to a panel on a transparent WinForm and make it visible? Here's the code I used, it's mostly for looking for errors (drawing the states and stuff).
void Draw()
{
while (true)
{
SolidBrush redpen = new SolidBrush(Color.Red);
Font font = new Font("Arial", 16);
PointF point = new PointF(700, 150);
Graphics g = panel1.CreateGraphics();
g.DrawString(Main.state.ToString(), font, redpen, point);
Main.beginTime.Stop();
Main.TimeRan = Main.beginTime.Elapsed;
string amountOfTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", Main.TimeRan.Hours, Main.TimeRan.Minutes, Main.TimeRan.Seconds, Main.TimeRan.Milliseconds / 10);
point = new PointF(700, 200);
g.DrawString(amountOfTime, font, redpen, point);
Thread.Sleep(10);
panel1.Refresh();
}
}
private void Form2_Shown(object sender, EventArgs e)
{
Draw();
}
Somewhere in my main class
// In a method
Thread F2T = new Thread(FormHandlers);
F2T.Start();
private void FormHandlers()
{
Form2 Form2 = new Form2();
Form2.Opacity = 0.00;
Form2.ShowDialog();
}
Edit: After some testing, I noticed that with the decrease of opacity the letter's opacity decreases as well, can I make it so the panel is transparent but the string I'm drawing to draw inside of it is not?
I guess you want to draw a message on a transparent child form? if that, I think you could do as follow: because the form.Opacity =0.00 makes all the controls in it be transparent, so we can't see anything. Another way, we use form.TransparencyKey to get that. code like this:
public Form2()
{
InitializeComponent();
//hide the border of form
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.BackColor = Color.White;
//set the TransparencyKey the same as the back color
this.TransparencyKey = this.BackColor;
}
protected override void OnPaint(PaintEventArgs e)
{
SolidBrush redpen = new SolidBrush(Color.Red);
Font font = new Font("Arial", 16);
PointF point = new PointF(400, 150);
Graphics g = e.Graphics;
string state = "running";
g.DrawString(state, font, redpen, point);
string amountOfTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", 1, 2, 3, 11111 / 10);
PointF point2 = new PointF(500, 150);
g.DrawString(amountOfTime, font, redpen, point2);
//base.OnPaint(e);
}
by the way, you want to show message in a child form, I don't prefer to use multi-threading, you just invoke the Form2 in Show() not in ShowDialog(), and set Form2.TopMost=True, than you can operate your main form as well. try it.
my result is bellow:
I am making an application in C# .NET. I have 8 picture boxes in it. I used PNG images with transparent background but in my form it is not transparent when it comes above another image.
I am using Visual Studio 2012. This is a screenshot of my form:
One way to do this is by changing the parent of the overlapping picture box to the PictureBox over which it is lapping. Since the Visual Studio designer doesn't allow you to add a PictureBox to a PictureBox, this will have to be done in your code (Form1.cs) and within the Intializing function:
public Form1()
{
InitializeComponent();
pictureBox7.Controls.Add(pictureBox8);
pictureBox8.Location = new Point(0, 0);
pictureBox8.BackColor = Color.Transparent;
}
Just change the picture box names to what ever you need. This should return:
GameBoard is control of type DataGridView;
The image should be type of PNG with transparent alpha channel background;
Image test = Properties.Resources.checker_black;
PictureBox b = new PictureBox();
b.Parent = GameBoard;
b.Image = test;
b.Width = test.Width*2;
b.Height = test.Height*2;
b.Location = new Point(0, 90);
b.BackColor = Color.Transparent;
b.BringToFront();
Try using an ImageList
ImageList imgList = new ImageList;
imgList.TransparentColor = Color.White;
Load the image like this:
picturebox.Image = imgList.Images[img_index];
I've had a similar problem like this.
You can not make Transparent picturebox easily such as picture that shown at top of this page, because .NET Framework and VS .NET objects are created by INHERITANCE! (Use Parent Property).
I solved this problem by RectangleShape and with the below code I removed background,
if difference between PictureBox and RectangleShape is not important and doesn't matter, you can use RectangleShape easily.
private void CreateBox(int X, int Y, int ObjectType)
{
ShapeContainer canvas = new ShapeContainer();
RectangleShape box = new RectangleShape();
box.Parent = canvas;
box.Size = new System.Drawing.Size(100, 90);
box.Location = new System.Drawing.Point(X, Y);
box.Name = "Box" + ObjectType.ToString();
box.BackColor = Color.Transparent;
box.BorderColor = Color.Transparent;
box.BackgroundImage = img.Images[ObjectType];// Load from imageBox Or any resource
box.BackgroundImageLayout = ImageLayout.Stretch;
box.BorderWidth = 0;
canvas.Controls.Add(box); // For feature use
}
One fast solution is set image property for image1 and set backgroundimage property to imag2, the only inconvenience is that you have the two images inside the picture box, but you can change background properties to tile, streched, etc. Make sure that backcolor be transparent.
Hope this helps
Just use the Form Paint method and draw every Picturebox on it, it allows transparency :
private void frmGame_Paint(object sender, PaintEventArgs e)
{
DoubleBuffered = true;
for (int i = 0; i < Controls.Count; i++)
if (Controls[i].GetType() == typeof(PictureBox))
{
var p = Controls[i] as PictureBox;
p.Visible = false;
e.Graphics.DrawImage(p.Image, p.Left, p.Top, p.Width, p.Height);
}
}
you can set the PictureBox BackColor proprty to Transparent
I have two windows forms. 1st one is mdiParent form named as main. 2nd one is presentation form which is the child form of main form. presentaion form has a tabbed layout. presentation form has a preferences button. when I click on preferences button a new form('prefs') opens asking to click on a set color button. clicking that button opens a dialogResult to change color. when I select a color, the prefs backcolor changes. but dows not changes the tabbed layout('presentation form') backcolor. I'm building this application in n-tier architecture. so help me how can I change the backcolor of a tab. I will upload code if you didn't understand my question.
TabControls do not have a BackColor property exposed since they typically draw based on the current window system theme.
It's usually not worth the effort, but the TabControl does has a DrawMode property where you would draw the tab yourself in the DrawItem event.
Each individual TabPage control does have a BackColor property available.
here's my custom event handler I have to create a colored box that surrounds the text. The selected tab is one color and unselected is another...
private void ChangeTabColor(Object sender, DrawItemEventArgs e)
{
Font TabFont;
Brush BackBrush;// = new SolidBrush(Color.Green); //Set background color
Brush ForeBrush = new SolidBrush(Color.Black);//Set foreground color
Brush borderBrush = new SolidBrush(Color.Black);//Set foreground color
if (e.Index == this.tabMain.SelectedIndex)
{
TabFont = new Font(e.Font, FontStyle.Bold);
BackBrush = new SolidBrush(Color.MediumSeaGreen); //Set background color
//ForeBrush = new SolidBrush(Color.Black);//Set foreground color
}
else
{
TabFont = e.Font;
BackBrush = new SolidBrush(Color.LightSteelBlue); //Set background color
//ForeBrush = new SolidBrush(Color.Yellow);//Set foreground color
}
string TabName = this.tabMain.TabPages[e.Index].Text;
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
Rectangle r = e.Bounds;
r = new Rectangle(r.X, r.Y + 5, r.Width, r.Height - 3);
if (e.Index == this.tabMain.SelectedIndex)
{
Pen rectPen = new Pen(borderBrush, 1.0f);
r.Y -= 2;
r.X += 3;
r.Height -= 9;
r.Width -= 8;
e.Graphics.FillRectangle(BackBrush, r);
e.Graphics.DrawString(TabName, TabFont, ForeBrush, r, sf);
e.Graphics.DrawRectangle(rectPen, r);
}
else
{
Pen rectPen = new Pen(borderBrush, 1.0f);
r.Y -= 2;
r.Height -= 4;
r.Width -= 2;
e.Graphics.FillRectangle(BackBrush, r);
e.Graphics.DrawString(TabName, TabFont, ForeBrush, r, sf);
e.Graphics.DrawRectangle(rectPen, r);
}
//Dispose objects
sf.Dispose();
if (e.Index == this.tabMain.SelectedIndex)
{
TabFont.Dispose();
BackBrush.Dispose();
}
else
{
BackBrush.Dispose();
ForeBrush.Dispose();
}
}
of course "tabMain" refers to the tab control name. I hope this helps with what you are trying to do...probably a bit fancier, but the code isn't that difficult, and I think it looks a bit cleaner...plus in order to do this i made sure to set the approprate properties for font and item size:
Font = Arial, 9pt, style=Bold
ItemSize = 95, 25
...the height is the important part, as long as you set SizeMode = Normal
I have custom tab control where OnPaint method is override.
Then strange growth of tabs occurs. Tabs getting bigger (padding getting bigger) and they width depends on length of the text.
When I use default Tab Control - padding is OK. How to avoid this situation when I use UserPaint?
partial class Tab : TabControl
{
public Tab()
{
InitializeComponent();
Init();
}
private void Init()
{
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
protected override void OnPaint(PaintEventArgs e)
{
DrawTabPane(e.Graphics);
}
private void DrawTabPane(Graphics g)
{
if (!Visible)
return;
// here we draw our tabs
for (int i = 0; i < this.TabCount; i++)
DrawTab(g, this.TabPages[i], i);
}
internal void DrawTab(Graphics g, TabPage tabPage, int nIndex)
{
Rectangle recBounds = this.GetTabRect(nIndex);
RectangleF tabTextArea = recBounds;
Point[] pt = new Point[4];
pt[0] = new Point(recBounds.Left + 1, recBounds.Bottom);
pt[1] = new Point(recBounds.Left + 1, recBounds.Top + 1);
pt[2] = new Point(recBounds.Right - 1, recBounds.Top + 1);
pt[3] = new Point(recBounds.Right - 1, recBounds.Bottom);
Brush br = new SolidBrush(clr_tab_norm);
g.FillPolygon(br, pt);
br.Dispose();
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
br = new SolidBrush(clr_txt);
g.DrawString(tabPage.Text, Font, br, tabTextArea, stringFormat);
}
}
Turning on ControlStyles.UserPaint for controls that are built into Windows, like TabControl, is not the proper thing to do. I assume the bug is in GetTabRect(), it isn't visible in the snippet.
Instead, you should use the TabControl.DrawMode property and implement the DrawItem event. There's a good example in the MSDN Library.
It would appear from the image that your code is setting the size of the tabs to be wider than they need to be. The extra padding is present in all your tabs but it is just more visible in the tabs with longer text.
I can't be sure why this is but I'd guess that the code to calculate the size of the tabs (based on font metrics) is using a different font from that used to draw the tabs.