- Hikaru {Aka} Yuuki のブログ - http://www.hikaruyuuki.com -
Membuat Tampilan Button Seperti Office 2010 dengan C#
Posted By Adikara Putra (Hikaru Yuuki) On 8日 5月 2011年 @ 17:03 In Pemrograman | No Comments
Di sini saya akan memberikan contoh untuk Owner Drawing/Painting pada suatu component/toolkit di aplikasi desktop (di web kita dapat dengan mudah menggunakan CSS). Kita dapat mendefinisikan tampilan yang berbeda layaknya kita mengaplikasikan theme pada component kita melalui beberapa cara. Misal Button yang awalnya biasa-biasa saja, bisa kita buat berwarna gradasi (gradient) dan tampil jauh lebih menarik.
Pada bahasa pemrograman berbeda mungkin akan ada perbedaan cara. Saya dulu sering coba-coba menggunakan Delphi, dan sekarang ini menggunakan WinForms C#, keduanya hampir sama terutama bila sudah kenal dengan Windows API (Java pun juga menggunakan logika yang sama). Salah satu cara melalui event painting (biasanya namanya event OnPaint) atau melalui class turunan Renderer, dengan ini kita bisa membuat suatu component/toolkit yang mempunyai tampilan seperti yang kita mau.
Dasarnya adalah metafora yang sama seperti di dunia nyata, kita nantinya akan melakukan proses Painting di Canvas. Setiap saat suatu component akan selalu dilukiskan di canvas supaya tampak secara visual di layar, singkat contohnya pada Button proses painting diawali dari pelukisan backgroundnya kemudian dilukiskan garis tepi (border) hingga muncul teks (bisa saja proses pelukisan akan berbeda urutannya). Hal ini dilakukan terus menerus supaya bisa tampak hingga akhirnya component tersebut di-destroy.
Contoh painting pada Button adalah sebagai berikut:
button1 di Form1.OnPaint pada Button (pilih Properties, di Events klik dua kali Paint) atau tambahkan di constructorForm, misal:
public Form1()
{
InitializeComponent();
button1.Paint += new System.Windows.Forms.PaintEventHandler(this.button1_Paint);
}
private void button1_Paint(object sender, PaintEventArgs e)
{
//variables
Color borderDark, borderLight, bgdark, bgmed, bglight,textColor;
int _roundedRadiusX = 3;
int _roundedRadiusY = 3;
//initialization
//blue button
borderDark = ColorFromHex("#1f48a1");
borderLight = ColorFromHex("#4487e4");
bgdark = ColorFromHex("#2961b5");
//bgmed = ColorFromHex("#3d7bd9");
bglight = ColorFromHex("#3e7ddb");
textColor = Color.White;
//////yellow button
//borderDark = ColorFromHex("#ecc757");
//borderLight = ColorFromHex("#fcf3d7");
//bgdark = ColorFromHex("#f9e189");
////bgmed = ColorFromHex("#3d7bd9");
//bglight = ColorFromHex("#fbf9e0");
//textColor = ColorFromHex("#1e395b");
//now let's we begin painting
Graphics g = e.Graphics;
//now let's we begin painting
//Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
Rectangle r = new Rectangle(e.ClipRectangle.Left,e.ClipRectangle.Top,e.ClipRectangle.Width,e.ClipRectangle.Height);
Rectangle r2 = r;
r2.Inflate(-1, -1);
Rectangle r3 = r2;
r3.Inflate(-1, -1);
//clear background first
using (SolidBrush br = new SolidBrush(Color.FromName("ButtonFace")))
{
g.FillRectangle(br, r);
}
//rectangle for gradient, half upper and lower
RectangleF halfup = new RectangleF(r.Left, r.Top, r.Width, r.Height);
RectangleF halfdown = new RectangleF(r.Left, r.Top + (r.Height / 2) - 1, r.Width, r.Height);
//BEGIN PAINT BACKGROUND
//for half upper, we paint using linear gradient
using (GraphicsPath thePath = GetRoundedRect(r, _roundedRadiusX, _roundedRadiusY))
{
LinearGradientBrush lgb =
new LinearGradientBrush(halfup, bglight, bgdark, 90f, true);
Blend blend = new Blend(4);
blend.Positions = new float[] { 0, 0.18f, 0.35f, 1f };
blend.Factors = new float[] { 0f, .4f, .9f, 1f };
lgb.Blend = blend;
g.FillPath(lgb, thePath);
lgb.Dispose();
//for half lower, we paint using radial gradient
using (GraphicsPath p = new GraphicsPath())
{
p.AddEllipse(halfdown); //make it radial
using (PathGradientBrush gradient = new PathGradientBrush(p))
{
gradient.WrapMode = WrapMode.Clamp;
gradient.CenterPoint = new PointF(Convert.ToSingle(halfdown.Left + halfdown.Width / 2), Convert.ToSingle(halfdown.Bottom));
gradient.CenterColor = bglight;
gradient.SurroundColors = new Color[] { bgdark };
blend = new Blend(4);
blend.Positions = new float[] { 0, 0.15f, 0.4f, 1f };
blend.Factors = new float[] { 0f, .3f, 1f, 1f };
gradient.Blend = blend;
g.FillPath(gradient, thePath);
}
}
//END PAINT BACKGROUND
//BEGIN PAINT BORDERS
using (GraphicsPath gborderDark = thePath)
{
using (Pen p = new Pen(borderDark, 1))
{
g.DrawPath(p, gborderDark);
}
}
using (GraphicsPath gborderLight = GetRoundedRect(r2, _roundedRadiusX, _roundedRadiusY))
{
using (Pen p = new Pen(borderLight, 1))
{
g.DrawPath(p, gborderLight);
}
}
using (GraphicsPath gborderMed = GetRoundedRect(r3, _roundedRadiusX, _roundedRadiusY))
{
SolidBrush bordermed = new SolidBrush(Color.FromArgb(50, borderLight));
using (Pen p = new Pen(bordermed, 1))
{
g.DrawPath(p, gborderMed);
}
}
//END PAINT BORDERS
//BEGIN PAINT TEXT
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
if (this.ShowKeyboardCues)
sf.HotkeyPrefix = HotkeyPrefix.Show;
else
sf.HotkeyPrefix = HotkeyPrefix.Hide;
g.DrawString((sender as Control).Text, (sender as Control).Font, new SolidBrush(textColor), e.ClipRectangle, sf);
}
}
public static GraphicsPath GetRoundedRect(RectangleF r, float radiusX, float radiusY)
{
GraphicsPath gp = new GraphicsPath();
gp.StartFigure();
r = new RectangleF(r.Left, r.Top, r.Width, r.Height);
if (radiusX <= 0.0F || radiusY <= 0.0F)
{
gp.AddRectangle(r);
}
else
{
//arcs work with diameters (radius * 2)
PointF d = new PointF(Math.Min(radiusX * 2, r.Width)
, Math.Min(radiusY * 2, r.Height));
gp.AddArc(r.X, r.Y, d.X, d.Y, 180, 90);
gp.AddArc(r.Right - d.X, r.Y, d.X - 1, d.Y, 270, 90);
gp.AddArc(r.Right - d.X, (r.Bottom) - d.Y - 1, d.X - 1, d.Y, 0, 90);
gp.AddArc(r.X, (r.Bottom) - d.Y - 1, d.X - 1, d.Y, 90, 90);
}
gp.CloseFigure();
return gp;
}
Untuk mengubah warna dari format hexadecimal ke Color:
public static Color ColorFromHex(string hex)
{
if (hex.StartsWith("#"))
hex = hex.Substring(1);
if (hex.Length != 6) throw new Exception("Color not valid");
return Color.FromArgb(
int.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber),
int.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber),
int.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber));
}
Sebagai catatan source code di atas tidak menggambarkan ketika ada perubahan state dari control, jadi ketika sedang di-sorot dengan mouse (mouse hover/enter) atau di klik (mouse down), dll maka gambarnya akan tetap saja. Supaya dapat menggambarkan perubahan setiap state, buat variable yang mencatat perubahan tersebut saat ada event OnMouseEnter, OnMouseLeave, OnMouseDown, ada focus, dll dan saat painting OnPaint cek state-nya dan lakukan painting yang berbeda tergantung dari state.
Dengan modal ini kita setidaknya dapat membuat tampilan pada custom control yang dapat kita buat sendiri.
Selamat berkreasi!
Article printed from Hikaru {Aka} Yuuki のブログ: http://www.hikaruyuuki.com
URL to article: http://www.hikaruyuuki.com/blog/membuat-tampilan-button-seperti-office-2010-dengan-c-sharp.html
URLs in this post:
[1] Your Ad Here: http://www.adbrite.com/mb/commerce/purchase_form.php?opid=1784967&afsid=1
[2] Your Ad Here: http://www.adbrite.com/mb/commerce/purchase_form.php?opid=1957137&afsid=1
[3] Image: http://www.hikaruyuuki.com/wp-content/uploads/button-painting.png
[4] Chrome Skin: Hyuu Chrome Office 2010: http://www.hikaruyuuki.com/blog/chrome-skin-hyuu-chrome-office-2010.html
[5] Bagaimana Membuat Drop Cap di Halaman Web: http://www.hikaruyuuki.com/blog/bagaimana-membuat-drop-cap-di-halaman-web.html
[6] Mengkompress Manual Javascript dan CSS dengan PHP GZip di .htaccess: http://www.hikaruyuuki.com/blog/mengkompress-manual-javascript-dan-css-dengan-deflate-di-htaccess.html
[7] Seminar: Opera Campus Crew UB dengan Etika dalam Jejaring Sosial di Dunia Maya: http://www.hikaruyuuki.com/blog/seminar-opera-campus-crew-ub-dengan-etika-dalam-jejaring-sosial-di-dunia-maya.html
Click here to print.
Copyright © 2011 Hikaru {Aka} Yuuki のブログ. All rights reserved.