how to give a panel its exact size in c#? - c#

I'm not an English user,so forgive me for grammatical problems please. Smile | :)
I have some paper forms that i want to print some labels on them.these papers have special size(24 cm * 14).so I made a panel(907 pixel * 529 pixel) and i put my labels on it(I converted cm to pixel and i put labels in the special parts of my panel).these labels are going to be printed in empty fields of my paper forms.but the problem is that, just the first form can be printed in the right style.others are printed in upper place of the form. I thought it may be because of I didn't give my panel and labels exact size in pixel. but i couldn't give my panel exact size in pixels,coz it doesn't accept pixels in decimal. any ideas?
this is a part of my code:
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
Pen blackPen = new Pen(Color.Black, 1);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.DrawLine(blackPen, 188, 400, 302, 400);
e.Graphics.DrawRectangle(blackPen, 330, 319, 122, 55);
e.Graphics.DrawString(label20.Text, label20.Font, new SolidBrush(label20.ForeColor), label20.Location);
e.Graphics.DrawString(label21.Text, label21.Font, new SolidBrush(label21.ForeColor), label21.Location);
e.Graphics.DrawString(label23.Text, label23.Font, new SolidBrush(label23.ForeColor), label23.Location);
e.Graphics.DrawString(label24.Text, label24.Font, new SolidBrush(label24.ForeColor), label24.Location);
e.Graphics.DrawString(label25.Text, label25.Font, new SolidBrush(label25.ForeColor), label25.Location);
e.Graphics.DrawString(label26.Text, label26.Font, new SolidBrush(label26.ForeColor), label26.Location);
e.Graphics.DrawString(label27.Text, label27.Font, new SolidBrush(label27.ForeColor), label27.Location);
e.Graphics.DrawString(lbl_kod.Text, lbl_kod.Font, new SolidBrush(lbl_kod.ForeColor), lbl_kod.Location);
e.Graphics.DrawString(lbl_ttarikh.Text, lbl_ttarikh.Font, new SolidBrush(lbl_ttarikh.ForeColor), lbl_ttarikh.Location);
e.Graphics.DrawString(lbl_ctot25.Text, lbl_ctot25.Font, new SolidBrush(lbl_ctot25.ForeColor), lbl_ctot25.Location);
e.Graphics.DrawString(lbl_pricetot25.Text, lbl_pricetot25.Font, new SolidBrush(lbl_pricetot25.ForeColor), lbl_pricetot25.Location);
e.Graphics.DrawString(lbl_pricetot.Text, lbl_pricetot.Font, new SolidBrush(lbl_pricetot.ForeColor), lbl_pricetot.Location);
e.Graphics.DrawString(lbl_pricetoth.Text, lbl_pricetoth.Font, new SolidBrush(lbl_pricetoth.ForeColor), lbl_pricetoth.Location);
e.Graphics.DrawString(lbl_name.Text, lbl_name.Font, new SolidBrush(lbl_name.ForeColor), lbl_name.Location);
e.Graphics.DrawString(lbl_dtarikh.Text, lbl_dtarikh.Font, new SolidBrush(lbl_dtarikh.ForeColor), lbl_dtarikh.Location);
}
and the print region for each paper form:
for (int i = 0; i < dataGridView1.RowCount && k < 3878; i++)
{
k = Convert.ToInt32(dataGridView1.Rows[i].Cells[0].Value);
bool found = false;
ctot25 = Convert.ToInt32(dataGridView1.Rows[i].Cells[13].Value);
ctot50 = Convert.ToInt32(dataGridView1.Rows[i].Cells[14].Value);
ctot100 = Convert.ToInt32(dataGridView1.Rows[i].Cells[15].Value);
foreach (object row1 in hoome)
if (row1.ToString() == (dataGridView1.Rows[i].Cells[0].Value).ToString())
{
found = true;
}
if (found == false)
{
if (i > 0 && ctot25 != 0 || ctot50 != 0 || ctot100 != 0)
{
#region tarikh
string date = dataGridView1.Rows[i].Cells[8].Value.ToString();
var aStringBuilder = new StringBuilder(date);
aStringBuilder.Insert(2, "/");
aStringBuilder.Insert(5, "/");
lbl_dtarikh.Text = aStringBuilder.ToString();
lbl_ttarikh.Text = datestringbuilder.ToString();
#endregion
decimal pricetot25;
pricetot25 = ctot25 * price25;
lbl_name.Text = (dataGridView1.Rows[i].Cells[1].Value).ToString();
lbl_kod.Text = (dataGridView1.Rows[i].Cells[0].Value).ToString();
lbl_ctot25.Text = (ctot25).ToString();
lbl_pricetot25.Text = (pricetot25).ToString();
lbl_pricetoth.Text = num2str(pricetot.ToString()) + " ریال" + "//";
#region print
System.Drawing.Printing.PrintDocument doc = new System.Drawing.Printing.PrintDocument();
doc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(printDocument1_PrintPage);
PrintDialog PrintSettings = new PrintDialog();
PrintSettings.Document = doc;
PageSettings pgsetting = new PageSettings();
doc.Print();
#endregion
}
}
}
here is a link to my screenshot:
my panel

Since your question is a little unclear, I think you better not to add your panel in design layout and create it programmatically. It'd be better if u take a screenshot of your second page.
EDIT:
Try creating labels in your FOR loop. You can drop panel in this way. I hope it works
if (found == false)
{
if (i > 0 && ctot25 != 0 || ctot50 != 0 || ctot100 != 0)
{
//Somthethin
Label lbl_Name = new Label { Location = new Point(50, 50), Text = (dataGridView1.Rows[i].Cells[1].Value).ToString() };
this.Controls.Add(lbl_Name);
//The rest of the codes
}
}

Related

Virtual Listview with pictures : How to fill all the column space with the picture

I'm trying to setup a listview with pictures.
As i have 3000+ items in that list i'm using the VirtualMode.
Here is my code :
ImageList il = new ImageList();
private void artistList_Load(object sender, EventArgs e)
{
var art_list = from res in Globals.ds.Tables[0].AsEnumerable()
.GroupBy(x => x.Field<int>("Artist_ID"))
.Select(x => new { artiste = x.Select(p => p.Field<string>("artiste")).First(), fp = x.Select(p => p.Field<string>("file_path")).First() })
.OrderBy(x=>x.artiste)
select res.fp;
fp = art_list.ToList();
int buffer = 20;
il.ImageSize = new Size(90, 90);
listView1.VirtualMode = true;
for (int i = 0; i< buffer; i++)
{
il.Images.Add(i.ToString(), Globals.getMp3Image(fp[i]));
}
listView1.LargeImageList = il;
listView1.VirtualListSize = fp.Count();
}
private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
if (e.Item == null) e.Item = new ListViewItem(e.ItemIndex.ToString());
e.Item.ImageIndex = il.Images.IndexOfKey(e.ItemIndex.ToString());
}
I'm using a buffer of 20 and i'll try to implement a cache mechanism later.
My issue is the visual result i'm getting, here is a picture :
I have several issues here :
1/ the number below the picture should be the index, but why is it displayed ?
2/ i'd like to expand the picture to the to avoid the white spaces in the 4 directions (there is some white spaces in the left)
3/ i'd like to avoid the horizontal scrollbar (but i think this issue is linked to #2)
Here is the Designer info : (the view is set to LargeIcon)
this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView1.HideSelection = false;
this.listView1.Location = new System.Drawing.Point(0, 0);
this.listView1.Margin = new System.Windows.Forms.Padding(0);
this.listView1.Name = "listView1";
this.listView1.ShowGroups = false;
this.listView1.Size = new System.Drawing.Size(137, 657);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.listView1_RetrieveVirtualItem);
Of course i've tried to set the Size of the listview at 90 but it's worst.

Remove controls of flowlayoutpanel and recreating it in C#

I had been experimenting on writing a code to generate images inside a FlowLayoutPanel.
This is what i had done so far, when i click on a button for the first time (by using a checkboxes - read in number of images to open), it will generate the images, when i click on the button on second try, it will not update the flowlayoutpanel.
Even though i tried to remove the controls inside the FlowLayoutPanel, it still doesn't show the second try of the images.
This is the code snippet of the method:
FlowLayoutPanel fwPanel = null;
private void btnOpenFile_Click(object sender, EventArgs e)
{
//if there is content inside the flowpanel, dump it
if (fwPanel != null)
{
listOfFile.Clear();
}
//create a new FLP
fwPanel = new FlowLayoutPanel();
int panelWidth = width * 4 + 50;
int panelHeight = height * 4 + 50;
fwPanel.Size = new Size(panelWidth, panelHeight);
fwPanel.Location = new Point(0, 0);
this.Controls.Add(fwPanel);
//each checked item would be stored into an arraylist
foreach(object itemChecked in clbFile.CheckedItems)
{
listOfFile.Add((clbFile.Items.IndexOf(itemChecked)+1).ToString());
}
int noOfCheckedFile = listOfFile.Count;
PictureBox[] listOfPicture = new PictureBox[noOfCheckedFile];
int positionX = 0, positionY = 0;
int maxPaddingX = (width * MATRIX_SIZE) - 1;
int maxPaddingY = (height * MATRIX_SIZE) - 1;
//dynamically create images.
for (int i = 0; i < noOfCheckedFile; i++)
{
listOfPicture[i] = new PictureBox();
listOfPicture[i].Image = resizeImage((Image)show_picture(Convert.ToInt32(listOfFile[i])), new Size(width, height));
listOfPicture[i].Size = new Size(width, height);
if (positionX > maxPaddingX)
{
positionX = 0;
positionY += height;
}
if (positionY > maxPaddingY)
{
positionY = 0;
}
listOfPicture[i].Location = new Point(positionX,positionY);
listOfPicture[i].Visible = true;
fwPanel.Controls.Add(listOfPicture[i]);
positionX += width;
}
}
show_picture is a method that takes in and integer and returns a bitmap image.
listOfFile is to trace which file to return.
listOfPicture is to store each images.
i tried replacing this lines
//if there is content inside the flowpanel, dump it
if (fwPanel != null)
{
listOfFile.Clear();
}
i have added this line into it, when i do a second click, everything just gone missing, but this is not what i want, because it does not re-populating the FlowLayoutPanel.
if (fwPanel != null)
{
fwPanel.SuspendLayout();
if (fwPanel.Controls.Count > 0)
{
for (int i = (fwPanel.Controls.Count - 1); i >= 0; i--)
{
Control c = fwPanel.Controls[i];
c.Dispose();
}
GC.Collect();
}
fwPanel.ResumeLayout();
listOfFile.Clear();
}
I also tried this, but on second click, nothing will happen.
if (fwPanel != null)
{
List<Control> listControls = fwPanel.Controls.Cast<Control>().ToList();
foreach (Control control in listControls)
{
fwPanel.Controls.Remove(control);
control.Dispose();
}
listOfFile.Clear();
}
I wonder if i miss out anything, can someone enlighten me on what did i miss out ? Or guide me for the best practice of doing this.
as Suggested, i shifted the creation outside (credit to Sinatr for spotting it)
FlowLayoutPanel fwPanel = new FlowLayoutPanel();
private void createFLP()
{
int panelWidth = width * 4 + 50;
int panelHeight = height * 4 + 50;
fwPanel.Size = new Size(panelWidth, panelHeight);
fwPanel.Location = new Point(0, 0);
this.Controls.Add(fwPanel);
}
that solves the nothing happen part. Followed by using this to remove controls
if (fwPanel != null)
{
List<Control> listControls = fwPanel.Controls.Cast<Control>().ToList();
foreach (Control control in listControls)
{
fwPanel.Controls.Remove(control);
control.Dispose();
}
listOfFile.Clear();
}
and everything works like a charm, hope that this answer will be able to help others who are facing the same problem too.

Dynamic GroupBoxes always align to top

I have this application where several groupboxes are in a vertical line. They can be enabled and disabled individually. I want to always align the groupboxes to the top, no matter if the ones normally being in between to is enabled or not.
Say we have three groupboxes (1, 2, 3). The middle one (2) gets disabled. Normally the two other boxes (1,3) locations wont be affected by this. But I want the last groupbox (3) to then take the place that the middle groupbox (2) would normally be in.
Any ideas how to accomplish this the most simple way?
This is what im doing at the moment which isnt good enough for scaling
if (isForgeIncluded == "True" | isForgeIncluded == "true")
{
forgeBox.Visible = true;
if (headerPic == "False" | headerPic == "false")
{
PictureBox1.Visible = false;
forgeBox.Location = new Point(6, 5);
pathBox.Location = new Point(6, 112);
}
else
{
}
}
else
{
forgeBox.Visible = false;
if (headerPic == "False" | headerPic == "false")
{
PictureBox1.Visible = false;
pathBox.Location = new Point(6, 5);
}
else
{
pathBox.Location = new Point(6, 168);
}
}
set groupbox2 location(x,y) to groupbox3 location(x,y) while your groupbox2 disables - might be from a specific event.
I managed to figure out a solution to this, which is "more dynamic" but not 100% dynamic, as i will have to go add new GroupBoxes to an array manually. However, this does work, and takes care of the picturebox in the beginning
int nextBoxLocation = 0;
int boxHeightAdd = 0;
int spacing = 6;
if (headerPic == "True" | headerPic == "true")
{
PictureBox1.Visible = true;
nextBoxLocation = PictureBox1.Height + spacing;
}
if (isForgeIncluded == "True" | isForgeIncluded == "true")
{
forgeBox.Visible = true;
}
GroupBox[] boxes = {forgeBox , pathBox , typeBox};
foreach(GroupBox box in boxes)
{
if (box.Visible == true)
{
box.Location = new Point(6, nextBoxLocation);
boxHeightAdd = box.Height;
}
if (box.Name == "pathBox" && (minecraftPathVar == Environment.ExpandEnvironmentVariables("C:\\Users\\" + Environment.UserName + "\\AppData\\Roaming\\.minecraft")))
{
defRadioPath.Visible = false;
minecraftRadioPath.Visible = false;
box.Height = 75;
boxHeightAdd = 75;
}
nextBoxLocation += boxHeightAdd + spacing;
boxHeightAdd = 0;
}

CellPaintingEvent of DataGridView

I am trying to highlight List of strings in my dataGrid view. For this purpose, I used the existing code that highlights a keyword in dataGridView. but resultant code only higlights last occurrence of the list (i.e. last record fetched).
Here is What I've tried
private void dvg_ClauseSent_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
foreach (string sw in HighlightStrings) // HighlightStringsis the list of string containing all strings I need to highlight in DataGrid view
{
int strt = 0;
int cnt = -1;
int idx = -1;
TextFormatFlags flags = TextFormatFlags.Default | TextFormatFlags.NoPrefix;
if ((((e.RowIndex >= 0) && (e.ColumnIndex >= 0))))
{
e.Handled = true;
e.PaintBackground(e.CellBounds, true);
if (!string.IsNullOrEmpty(sw))
{
string val = e.FormattedValue.ToString();
int sindx = val.IndexOf(sw);
if ((sindx >= 0))
{
while (strt != -1)
{
strt = val.IndexOf(sw, idx + 1);
cnt += 1;
idx = strt;
if (strt != -1)
{
if (strt != 0 && ((strt + sw.Length) != val.Length))
{
Rectangle hl_rect = new Rectangle();
hl_rect.Y = (e.CellBounds.Y + 2);
hl_rect.Height = (e.CellBounds.Height - 5);
// find the size of the text before the search word
// and the size of the search word
// paint the background behind the search word
e.Graphics.FillRectangle(hl_brush, hl_rect);
hl_brush.Dispose();
}
}
}
}
}
}
// paint the content as usual
e.PaintContent(e.CellBounds);
}
}
Attached ScreenShots
Following screenshot shows the strings that should appear as highligted in dataGridView
http://i42.tinypic.com/2dtrea1.png
Part of strings enclosed in ANGLE BRACKET followed/preceeded by |* / *| should be appeared as highlighted but only last entry is being highlighted.
http://i39.tinypic.com/30cbw9l.png
Any help will be appreciated...
Your code has this strange thing:
Rectangle hl_rect = new Rectangle();
hl_rect.Y = (e.CellBounds.Y + 2);
hl_rect.Height = (e.CellBounds.Height - 5);
You don't even initialize the X and the Width (hence they will be empty by default). So how could it be rendered???
I would like to talk this to everyone who will be asking questions, please post your actual code. Don't try simplifying it if you don't understand how wrong it is after being simplified. Except the code above, I don't find any thing which may cause the issue (it's of course not tested, just a quick scan). I've tried writing another code for you, also tested. The problem is we have to draw the string and measure the string together so that the Text Bound can be determined exactly. The TextRenderingHint.AntiAlias should also be used, although sometimes it works without that. The drawn text may look a little blurry however it can be partially eliminated by using a large font, the larger the better. Here is the code for you.
private void dataGridView1_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e) {
if (e.RowIndex > -1 && e.ColumnIndex > -1 && e.Value != null) {
string value = e.Value.ToString();
foreach (var s in HighlightStrings) {
int i = 0;
while (i < value.Length && (i = value.IndexOf(s,i))!=-1) {
if (!e.Handled){
e.Handled = true;
e.PaintBackground(e.ClipBounds, true);
}
StringFormat sf = StringFormat.GenericTypographic;
sf.LineAlignment = StringAlignment.Center;
RectangleF textBounds = GetTextBounds(e.Graphics,
value, i, s.Length,
e.CellBounds,
e.CellStyle.Font, sf);
//highlight it
e.Graphics.FillRectangle(Brushes.Yellow, textBounds);
i += s.Length;
using (Brush brush = new SolidBrush(e.CellStyle.ForeColor)) {
//draw string , don't use PaintContent
e.Graphics.DrawString(value, e.CellStyle.Font, brush,
e.CellBounds, sf);
}
}
}
}
}
public RectangleF GetTextBounds(Graphics g, string text,
int subIndex, int subLength,
RectangleF layout,
Font font, StringFormat sf) {
var charRange = new CharacterRange(0, text.Length);
var subCharRange = new CharacterRange(subIndex, subLength);
sf.SetMeasurableCharacterRanges(new[]{ charRange, subCharRange });
var regions = g.MeasureCharacterRanges(text, font, layout, sf);
return regions.Length < 2 ? RectangleF.Empty : regions[1].GetBounds(g);
}
NOTE: The reason we have to use DrawString is as I said to measure the TextBound exactly. If you have some way to measure it exactly without having to draw the string yourself, you can use PaintContent.

Display an image as I manipulate it

I am writing a C# program to do some scanning of the pixels in an image. This is for a program I am only going to run maybe 5 times so does not need to be efficient.
After reading each pixel I want to change it's colour and update the display of the image so I can see the scans progress and what it is finding, but I can't get anything to display. Has anyone done something like this before or know of a good example?
Edit:
The code I am trying to use at the moment is.
void Main()
{
Bitmap b = new Bitmap(#"C:\test\RKB2.bmp");
Form f1 = new Form();
f1.Height = (b.Height /10);
f1.Width = (b.Width / 10);
PictureBox PB = new PictureBox();
PB.Image = (Image)(new Bitmap(b, new Size(b.Width, b.Height)));
PB.Size = new Size(b.Width /10, b.Height /10);
PB.SizeMode = PictureBoxSizeMode.StretchImage;
f1.Controls.Add(PB);
f1.Show();
for(int y = 0; y < b.Height; y++)
{
for(int x = 0; x < b.Width; x++)
{
if(b.GetPixel(x,y).R == 0 && b.GetPixel(x,y).G == 0 && b.GetPixel(x,y).B == 0)
{
//color is black
}
if(b.GetPixel(x,y).R == 255 && b.GetPixel(x,y).G == 255 && b.GetPixel(x,y).B == 255)
{
//color is white
Bitmap tes = (Bitmap)PB.Image;
tes.SetPixel(x, y, Color.Yellow);
PB.Image = tes;
}
}
}
}
You need to separate the image processing action and the update action. A good start would be to create a Windows Forms project, add the PictureBox control to the form and a button. Bind the button to an action and in the action start the processing. Then the update process will be visible. When your code is changed to this, then the final transformation should be visible:
void Main()
{
Bitmap b = new Bitmap(#"C:\test\RKB2.bmp");
Form f1 = new Form();
f1.Height = (b.Height /10);
f1.Width = (b.Width / 10);
// size the form
f1.Size = new Size(250, 250);
PictureBox PB = new PictureBox();
PB.Image = (Image)(new Bitmap(b, new Size(b.Width, b.Height)));
PB.Size = new Size(b.Width /10, b.Height /10);
PB.SizeMode = PictureBoxSizeMode.StretchImage;
PB.SetBounds(0, 0, 100, 100);
Button start = new Button();
start.Text = "Start processing";
start.SetBounds(100, 100, 100, 35);
// bind the button Click event
// The code could be also extracted to a method:
// private void startButtonClick(object sender, EventArgs e)
// and binded like this: start.Click += startButtonClick;
start.Click += (s, e) =>
{
for(int y = 0; y < b.Height; y++)
{
for(int x = 0; x < b.Width; x++)
{
if(b.GetPixel(x,y).R == 0 && b.GetPixel(x,y).G == 0 && b.GetPixel(x,y).B == 0)
{
//color is black
}
if(b.GetPixel(x,y).R == 255 && b.GetPixel(x,y).G == 255 && b.GetPixel(x,y).B == 255)
{
//color is white
Bitmap tes = (Bitmap)PB.Image;
tes.SetPixel(x, y, Color.Yellow);
PB.Image = tes;
}
}
}
};
f1.Controls.Add(PB);
f1.Controls.Add(start);
f1.Show();
}
After the change the result (with my test image) looks like this:

Categories