I have a project in which you can add and remove tabs (like a web browser). So far I have this:
//Button to add a new tab page
private void cb_addPage_Click(object sender, EventArgs e)
{
string title = "TabPage " + (tabControl1.TabCount + 1).ToString() + " ";
TabPage myTabPage = new TabPage(title);
tabControl1.TabPages.Add(myTabPage);
tabControl1.SelectedTab = myTabPage;
}
//Form1_Load
private void Form1_Load(object sender, EventArgs e)
{
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
cb_addPage.Top = tabControl1.Top;
cb_addPage.Left = tabControl1.Right - cb_addPage.Width;
foreach (TabPage tp in tabControl1.TabPages) tp.Text += " ";
}
Rectangle closeX = Rectangle.Empty;
//Sets background and places the X button on each tab
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Size xSize = new Size(15, 15);
TabPage tp = tabControl1.TabPages[e.Index];
e.DrawBackground();
using (SolidBrush brush = new SolidBrush(e.ForeColor))
e.Graphics.DrawString(tp.Text + " ", e.Font, brush,
e.Bounds.X + 3, e.Bounds.Y + 4);
if (e.State == DrawItemState.Selected)
{
closeX = new Rectangle(e.Bounds.Right - xSize.Width - 3,
e.Bounds.Top + 5, xSize.Width, xSize.Height);
e.Graphics.DrawImage(imageList1.Images[0], closeX,
new Rectangle(0,0,16,16), GraphicsUnit.Pixel );
}
}
//Removes current tab (from X button)
private void tabControl1_MouseClick(object sender, MouseEventArgs e)
{
if (closeX.Contains(e.Location))
tabControl1.TabPages.Remove(tabControl1.SelectedTab);
}
So all this does is let you add tabs with a button and on each individual tab there is an X button to delete the tab.
I have used Graphics.DrawImage to display the custom X button (that are in an imageList). However how will I go about making custom tabs using Graphics.DrawImage.
To sum up I want tabs, but I want them to be custom images that I have made so it looks better. - Thanks
Your question is not very clear. Probably you want to display a different text on each tab. You can use the TextRenderer to do so:
const TextFormatFlags flags = TextFormatFlags.PreserveGraphicsClipping |
TextFormatFlags.VerticalCenter;
TextRenderer.DrawText(e.Graphics, tp.Text, tp.Font, e.Bounds, tp.ForeColor, flags);
Either prepend some spaces to the text in order to leave space for the X or define new coordiantes for the text
const int XCrossWidth = 20;
Rectangle textRect = new Rectangle(e.Bounds.Left + XCrossWidth, e.Bounds.Top,
e.Width - XCrossWidth, e.Height);
and substitue this for e.Bounds in TextRenderer.DrawText(...).
UPDATE
So you want to display custom images on your tabs. I assume that you have placed these images in the imageList1. How do you know which of them to display on which TabPage?
You could create your own tab page class and use this one instead of TabPage.
public TabPageEx : TabPage
{
public int ImageIndex { get; set }
}
Now set the property to the appropriate image index.
TabPageEx myTabPage = new TabPageEx(title);
myTabPage.ImageIndex = 3; // As an example.
tabControl1.TabPages.Add(myTabPage);
Then you can draw the image with
TabPageEx tp = (TabPageEx)tabControl1.TabPages[e.Index];
...
Rectangle imageRect = new Rectangle(e.Bounds.Left + 20, 0, 16, 16);
e.Graphics.DrawImage(imageList1.Images[tp.ImageIndex], imageRect);
If you want to display Images in addition to the text like a webbrowsers favicon you can use this modified code:
private void tabControl3_DrawItem(object sender, DrawItemEventArgs e)
{
Size xSize = new Size(16,16);
Point imgLoc = new Point(e.Bounds.X + 4, e.Bounds.Y + 4);
TabPage tp = tabControl3.TabPages[e.Index];
e.DrawBackground();
e.Graphics.DrawImage(imageList1.Images[tp.ImageIndex], new Rectangle(imgLoc, xSize),
new Rectangle(Point.Empty, xSize), GraphicsUnit.Pixel);
using (SolidBrush brush = new SolidBrush(e.ForeColor))
{
e.Graphics.DrawString(tp.Text + " ", e.Font, brush,
e.Bounds.X + 23, e.Bounds.Y + 4);
if (e.State == DrawItemState.Selected)
{
closeX = new Rectangle(e.Bounds.Right - xSize.Width - 3,
e.Bounds.Top + 5, xSize.Width, xSize.Height);
e.Graphics.DrawImage(imageList1.Images[0], closeX,
new Rectangle(Point.Empty, xSize), GraphicsUnit.Pixel);
}
}
}
You need to make sure that:
You have those images you want to show in each tab in your imagelist.
and you know the index of ech one.
Youi must set it when you create the page but you can always change it later.
It is a good idea to have a default icon at index 0 and to set the imageindex to 0 for those you don't know the right index.
Usually you would also have to make your Tab control point to the Imagelist. But since we are drawing it all by ourselves, this is not important.
You can use the more complex format of DrawString, that is used for drawing the close button. Here you don't just use a point to determine the location where to draw; instead this format uses two rectangles to determine the source and the target. This effectively leads to th option of scaling the image to a new size.
But you'll get the best quality if your Images have the right size to begin with. Please note that the text of each TabPage determines the width of the tab; to make it higher you need to chose a larger Fontsize.
Related
I am trying to add close button or 'X' on tabpage panel in tabcontrol and I have successfully done this by reading this stackoverflow question.
The problem is the tabbed page title and X sign is merged together. I discovered that the tabpage title panel is not resizing according to title text.
Here is the code:
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("X", e.Font, Brushes.Black, e.Bounds.Right + 15, e.Bounds.Top + 4);
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left+5, e.Bounds.Top + 4);
e.DrawFocusRectangle();
The result which comes is here I have changed e.bounds.right value but still it's not working.
To fix merged tabPage.Text with additionally drawed "X" just add:
tabControl.Padding = new System.Drawing.Point(21, 3);
It will add some extra space to the end of every tabPage
Make sure you set the DrawMode property of the Tab Control to OwnerDrawFixed. This property is decides whether system or developer painting the captions.
Here is code example that uses TabSizeMode = Fixed is setting the tab size:
public partial class Form1 : Form
{
const int LEADING_SPACE = 12;
const int CLOSE_SPACE = 15;
const int CLOSE_AREA = 15;
public Form1()
{
InitializeComponent();
}
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("x", e.Font, Brushes.Black, e.Bounds.Right - CLOSE_AREA, e.Bounds.Top + 4);
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left + LEADING_SPACE, e.Bounds.Top + 4);
e.DrawFocusRectangle();
}
private void Form1_Load(object sender, EventArgs e)
{
// get the inital length
int tabLength = tabControl1.ItemSize.Width;
// measure the text in each tab and make adjustment to the size
for (int i = 0; i < this.tabControl1.TabPages.Count; i++)
{
TabPage currentPage = tabControl1.TabPages[i];
int currentTabLength = TextRenderer.MeasureText(currentPage.Text, tabControl1.Font).Width;
// adjust the length for what text is written
currentTabLength += LEADING_SPACE + CLOSE_SPACE + CLOSE_AREA;
if (currentTabLength > tabLength)
{
tabLength = currentTabLength;
}
}
// create the new size
Size newTabSize = new Size(tabLength, tabControl1.ItemSize.Height);
tabControl1.ItemSize = newTabSize;
}
}
Screen shot of sample code from above:
While trying to change the color of the tab based on button click event I came across this page:
Set TabPage Header Color
It appears to work, however I lost all the other formatting of my tabs and they now appear blank after I set the DrawMode=OwnerDrawFixed. How do I set the color of the tab of a specific page and still show the tabs as normal?
Code:
private void button3_Click(object sender, EventArgs e)
{
this.TabControlMain.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.TabControlMain_DrawItem);
SetTabHeader (tabDownload, System.Drawing.Color.Green);
}
private Dictionary<TabPage, Color> TabColors = new Dictionary<TabPage, Color>();
private void SetTabHeader(TabPage page, Color color)
{
TabColors[page] = color;
tabDownload.Invalidate();
}
private void TabControlMain_DrawItem(object sender, DrawItemEventArgs e)
{
//e.DrawBackground();
using (Brush br = new SolidBrush(TabColors[TabControlMain.TabPages[e.Index]]))
{
e.Graphics.FillRectangle(br, e.Bounds);
SizeF sz = e.Graphics.MeasureString(TabControlMain.TabPages[e.Index].Text, e.Font);
e.Graphics.DrawString(TabControlMain.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left + (e.Bounds.Width - sz.Width) / 2, e.Bounds.Top + (e.Bounds.Height - sz.Height) / 2 + 1);
Rectangle rect = e.Bounds;
rect.Offset(0, 1);
rect.Inflate(0, -1);
e.Graphics.DrawRectangle(Pens.DarkGray, rect);
e.DrawFocusRectangle();
}
}
Below is a screenshot
Use Y(et)A(nother)TabControl
Gives you the possibly to draw own custom headers:
public override void DrawTab( Color foreColor,
Color backColor,
Color highlightColor,
Color shadowColor,
Color borderColor,
bool active,
bool mouseOver,
DockStyle dock,
Graphics graphics,
SizeF tabSize )
{
if( active )
{
Pen p = new Pen( borderColor );
graphics.DrawRectangle( p, 0, 0, tabSize.Width, tabSize.Height );
p.Dispose();
}
else
{
Brush b = Brushes.Peru;
float dif = tabSize.Height / 4.0f;
RectangleF r = new RectangleF( 0.0f, dif,
tabSize.Width, tabSize.Height - dif - dif );
graphics.FillRectangle( b, r );
}
}
In principle your code works, if not fine then at least sufficiently.
But you need to fix a few simple issues:
Of course, if your Tab is OwnerDrawn you need to do it from the start, not just after pressing the Button! So hook up the event right from the start, best in the Property-Event Tab so that it is placed in the Desgner.cs file where it belongs.
Now the Tabs are drawn and their Label texts show.
If you want to change a color you need to Invalidate the Tab Control, not the TabPage!
so change
tabDownload.Invalidate();
to
TabControlMain.Invalidate();
To make the example complete I have done only this:
private void Form1_Load(object sender, EventArgs e)
{
foreach (TabPage tp in TabControlMain.TabPages)
TabColors.Add(tp, tp.BackColor);
}
This sets all Tab colors in the Dictionary to the Colors of the Pages.
The code to draw the FocusRectangle could be improved.
First set the Padding like this:
this.TabControlMain.Padding = new System.Drawing.Point(10, 4);
This gives us enough room to draw a nice FocusRectangle..
Then change the code to draw it only on the selected Tab, maybe like this:
if (TabControlMain.SelectedIndex == e.Index)
using (Pen pen = new Pen(Color.Gray))
{
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
Rectangle rect = e.Bounds;
rect.Offset(0, 1);
rect.Inflate(-3,-2);
e.Graphics.DrawRectangle(pen, rect);
}
Now it looks like this:
Of course managing the colors is up to you..
This question already has answers here:
Close button for TabPages of Right To Left TabControl c#
(2 answers)
Closed 6 years ago.
I wanted to add X button for each tab.
The drawMode is OwnerDrawFixed. it works fine if it left to right.
Once I allow RightToLeftLayout = true and RightToLeft = true, it does not look good because that he still adds the string from left to right, while that tab add from right to left.
How do I make it that string will also be right to left?
private void addCloseButton(object sender, DrawItemEventArgs e)
{
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("x", e.Font, Brushes.Black, e.Bounds.Right - 15 , e.Bounds.Top +4 );
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left+4, e.Bounds.Top+4);
e.DrawFocusRectangle();
}
private void actionClose(object sender, MouseEventArgs e)
{
//Looping through the controls.
for (int i = 0; i < this.tabControl1.TabPages.Count; i++)
{
Rectangle r = tabControl1.GetTabRect(i);
//Getting the position of the "x" mark.
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 10);
if (closeButton.Contains(e.Location))
{
if (MessageBox.Show("?האם אתה רוצה לסגור טאב זה", "אישור", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
this.tabControl1.TabPages.RemoveAt(i);
break;
}
}
}
}
Pass StringFormat with FormatFlags flag set to StringFormatFlags.DirectionRightToLeft to the DrawString():
StringFormat drawFormat = new StringFormat(StringFormatFlags.DirectionRightToLeft);
var bounds = new RectangleF(.. set actual bound rectangle for text... )
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, bounds, drawFormat);
check here http://www.microsoft.com/middleeast/msdn/visualstudio2005.aspx you should use textrenderer instead of drawstring
I found an article that does exactly what I need. It draws multiple colors on the same line on a text box. But the problem is that it was written in VB.NET and I'm writing my program in C#. Any good soul can convert this to C# if it is possible and if it isn't can you give me other options? Thanks.
This is the article: http://www.vbrad.com/article.aspx?id=34.
here is the conversion of what you posted Nicolas
if you need to change / get anything else working you will need to test it on your end..
Happy coding
private void MeasureItemHandler(object sender, MeasureItemEventArgs e)
{
Graphics g = Graphics.FromHwnd(lstColor.Handle);
StringFormat sf = new StringFormat(StringFormat.GenericTypographic);
SizeF size = default(SizeF);
float height = 0;
Font oFont = new Font("Arial", 10);
//measure the height of what you are about to draw
//and let the listbox know this
size = g.MeasureString(data(e.Index), oFont, 500, sf);
height = size.Height + 5;
e.ItemHeight = height;
}
private void DrawItemHandler(object sender, DrawItemEventArgs e)
{
Graphics g = Graphics.FromHwnd(lstColor.Handle);
StringFormat sf = new StringFormat(StringFormat.GenericTypographic);
SizeF size = default(SizeF);
float width = 0;
Font oFont = new Font("Arial", 10);
//get the width of the string you are about to write
//this info is needed so that we can offset the next
//string that will be drawn in a different color.
size = g.MeasureString(data(e.Index), oFont, 500, sf);
width = size.Width + 16;
//prepare the list for drawing
e.DrawBackground();
e.DrawFocusRectangle();
//draw the first string in a certain color
e.Graphics.DrawString(data(e.Index), oFont, new SolidBrush(color(e.Index)), e.Bounds.X, e.Bounds.Y);
//draw the second string in a different color
e.Graphics.DrawString(data(data.Length - 1 - e.Index), oFont, new SolidBrush(color(color.Length - 1 - e.Index)), width, e.Bounds.Y);
}
First of all, they aren't using a Textbox in this article, they are using a Listbox but what follows is a conversion of the code from VB.Net to C# like you asked. It needs tidied up a bit but it does the job.
Just create a new Windows Form, place a Listbox called lstColor onto this form, change the DrawMode property to OwnerDrawFixed inside the properties window, then add event handlers for DrawItem and MeasureItem (you can add event handlers by clicking on the lightning bolt in the Properties window, and double clicking the whitespace beside these two words in the list).
In the DrawItem event handler, add the following:
private void lstColor_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
var size = g.MeasureString(data[e.Index], oFont, 500, sf);
var width = size.Width + 16;
e.DrawBackground();
e.DrawFocusRectangle();
e.Graphics.DrawString(data[e.Index], oFont, new SolidBrush(color[e.Index]), e.Bounds.X, e.Bounds.Y);
e.Graphics.DrawString(data[data.Length - 1 - e.Index], oFont, new SolidBrush(color[color.Length - 1 - e.Index]), width, e.Bounds.Y);
}
In the MeasureItem event handler, add this:
private void lstColor_MeasureItem(object sender, MeasureItemEventArgs e)
{
var size = g.MeasureString(data[e.Index], oFont, 500, sf);
var height = size.Height;
e.ItemHeight = Convert.ToInt32(height);
}
Add five private fields outside the scope of any methods but inside your Form1 (or whatever you've called your form) class like so:
private string[] data;
private Color[] color;
private Font oFont;
private Graphics g;
private StringFormat sf;
Put the following three lines inside your Form1_Load event:
private void Form1_Load(object sender, EventArgs e)
{
oFont = new Font("Arial", 10);
data = new string[] { "This is Red", "This is Blue", "This is Green", "This is Yellow", "This is Black", "This is Aqua", "This is Brown", "This is Cyan", "This is Gray", "This is Pink" };
color = new Color[] {Color.Red, Color.Blue, Color.Green, Color.Yellow, Color.Black, Color.Aqua, Color.Brown, Color.Cyan, Color.Gray,Color.Pink};
lstColor.DataSource = data;
g = Graphics.FromHwnd(lstColor.Handle);
sf = new StringFormat(StringFormat.GenericTypographic);
}
And you are all set.
Hope this helps
Check out http://converter.telerik.com/ It converts code from VB.NET to C# and C# to VB.NET. It wont work on complex code, but could prove useful to you.
is there anyone can tell me how to add close button in each tab in using tabControl in C#?
i plan to use button pic for replacing [x] in my tab..
thank you
Without deriving a class, here is a neat snippet:
http://www.dotnetthoughts.net/implementing-close-button-in-tab-pages/
Set the DrawMode property of the Tab Control to OwnerDrawFixed. This property decides whether system or developer can paint the captions.
Add the code in the DrawItem event of the Tab Control – This event will be invoked for painting each Tab Page.
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("x", e.Font, Brushes.Black, e.Bounds.Right - 15, e.Bounds.Top + 4);
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left + 12, e.Bounds.Top + 4);
e.DrawFocusRectangle();
Now for close button action, we need to add the following code to the MouseDown event of the Tab Control.
//Looping through the controls.
for (int i = 0; i < this.tabControl1.TabPages.Count; i++)
{
Rectangle r = tabControl1.GetTabRect(i);
//Getting the position of the "x" mark.
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 9, 7);
if (closeButton.Contains(e.Location))
{
if (MessageBox.Show("Would you like to Close this Tab?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
this.tabControl1.TabPages.RemoveAt(i);
break;
}
}
}
Adding to the other answers... why iterating through all the tabs on mouse click event when we can just detect the current tab with .SelectedIndex and .SelectedTab ?
Like so:
private void tabControl1_MouseDown(object sender, MouseEventArgs e)
{
Rectangle r = tabControl1.GetTabRect(this.tabControl1.SelectedIndex);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 9, 7);
if (closeButton.Contains(e.Location))
{
this.tabControl1.TabPages.Remove(this.tabControl1.SelectedTab);
}
}
What seems to happen is, the moment you click on a tabPage for closing it, it also gets selected, thus allowing the close button to close the right tabPage.
To me it works but please take this with extra care though as I am not completely sure of possible drawbacks (my initial sentence wasn't a completely rhetorical question since I'm kinda new to .Net...).
Try this code:
private Point _imageLocation = new Point(13, 5);
private Point _imgHitArea = new Point(13, 2);
private void Form1_Load(object sender, EventArgs e)
{
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
tabControl1.DrawItem += tabControl1_DrawItem;
CloseImage = WindowsFormsApplication3.Properties.Resources.closeR;
tabControl1.Padding = new Point(10, 3);
}
private void TabControl1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
try
{
Image img = new Bitmap(CloseImage);
Rectangle r = e.Bounds;
r = this.tabControl1.GetTabRect(e.Index);
r.Offset(2, 2);
Brush TitleBrush = new SolidBrush(Color.Black);
Font f = this.Font;
string title = this.tabControl1.TabPages[e.Index].Text;
e.Graphics.DrawString(title, f, TitleBrush, new PointF(r.X, r.Y));
if (tabControl1.SelectedIndex >= 1)
{
e.Graphics.DrawImage(img, new Point(r.X + (this.tabControl1.GetTabRect(e.Index).Width - _imageLocation.X), _imageLocation.Y));
}
}
catch (Exception) { }
}
private void TabControl1_Mouse_Click(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
TabControl tc = (TabControl)sender;
Point p = e.Location;
int _tabWidth = 0;
_tabWidth = this.tabControl1.GetTabRect(tc.SelectedIndex).Width - (_imgHitArea.X);
Rectangle r = this.tabControl1.GetTabRect(tc.SelectedIndex);
r.Offset(_tabWidth, _imgHitArea.Y);
r.Width = 16;
r.Height = 16;
if (tabControl1.SelectedIndex >= 1)
{
if (r.Contains(p))
{
TabPage TabP = (TabPage)tc.TabPages[tc.SelectedIndex];
tc.TabPages.Remove(TabP);
}
}
}
Look at this code snippet
I ran into this same issue, however, I also wanted to have an image in front of the caption on the tab. Here is the code that will give you an image in front, a caption and a close button. Also, this code includes the ability to use the middle mouse click on the tab to close it.
First under the TabControl's properties change DrawMode from Normal to OwnerDrawFixed. Next, you will need to tweak the X dimension for the TabControl's padding also found under properties.
In this example, my TabControl is called "TabManager" so rename that to the name of your control.
Go under the envents (the little lightning bolt near the top of the properties box) and double click in the white box next to "DrawItem", this will create a trigger. In that method use this code with your adjustments.
private void TabManager_DrawItem(object sender, DrawItemEventArgs e)
{
TabPage thisTab = TabManager.TabPages[e.Index];
string tabTitle = thisTab.Text;
Image icon = imageList1.Images[thisTab.ImageIndex];
//Draw Close button
Point closeLoc = new Point(15, 5);
e.Graphics.DrawRectangle(Pens.Black, e.Bounds.Right - closeLoc.X, e.Bounds.Top + closeLoc.Y, 10, 12);
e.Graphics.FillRectangle(Brushes.LightBlue, e.Bounds.Right - closeLoc.X, e.Bounds.Top + closeLoc.Y, 10, 12);
e.Graphics.DrawString("x", e.Font, Brushes.Black, e.Bounds.Right - (closeLoc.X), e.Bounds.Top + closeLoc.Y-2);
// Draw String of Caption
e.Graphics.DrawString(tabTitle, e.Font, Brushes.Black, e.Bounds.Left + 28, e.Bounds.Top + 4);
// Add Icon to Front
e.Graphics.DrawImage(icon, e.Bounds.Left + 6, e.Bounds.Top + 3);
e.DrawFocusRectangle();
}
Next go back to the events and double click on the white box next to MouseDown. Then use this code:
private void TabManager_MouseDown(object sender, MouseEventArgs e)
{
Point closeLoc = new Point(15, 5);
Rectangle r = TabManager.GetTabRect(TabManager.SelectedIndex);
Rectangle closeButton = new Rectangle(r.Right - closeLoc.X, r.Top + closeLoc.Y, 10, 12);
if (closeButton.Contains(e.Location))
{
TabManager.TabPages.Remove(TabManager.SelectedTab);
return; // Don't keep running logic in method
}
for (int i = 0; i < TabManager.TabCount; i++)
{
r = TabManager.GetTabRect(i);
if (r.Contains(e.Location) && e.Button == MouseButtons.Middle)
{
TabManager.TabPages.RemoveAt(i);
}
}
}