I currently have some images (4) in front of a image background, the problem is, the image shape, collides with the other ones and the transparency it's not working well between them.
Ok, i have set the backcolor for those 4 images to Transparent, and then, set the parent for each one the back image, but this is what I see:
Imgur
It seems that only refresh their parent (Background) some help?
I suspect that you're adding pictureboxes or something similar , but this will make it very inefficient to work with.
You might want to consider creating an object which will take care of the image draw and add it to you base control which has you background image, something like this:
public class YellowGuy
{
public Point Position {get; set;}
public Size Size {get; set;}
public Bitmap YellowGuyImage {get; set;}
public YellowGuy(Bitmap img, Point startPos, Size desiredSize)
{
YellowGuyImage = img;
Size = desiredSize;
Position = startPos;
}
public void Draw(Graphics g)
{
g.DrawImage(YellowGuyImage, new rectangle(Position, Size));
}
}
In you main form (maybe, I don't know your code):
picturebox.Paint += new System.Windows.Forms.PaintEventHandler(this.picturebox_Paint);
List<YellowGuy> yellowGuys;
yellowGuys = new List<YellowGuy>();
yellowGuys.Add(new YellowGuy([some image],[some position],[some size])); //Do on a for, or how you wish, to add more guys.
//Control which draw images, here I used PictureBox to show you
private void picturebox_Paint(object sender, PaintEventArgs e)
{
foreach(var guy in yellowGuys)
{
guy.Draw(e.Graphics);
}
}
You can just re-position a yellow guy accessing list and changing position and on the next refresh it will be drawn in the new position.
You might want to add an ID or Name to YellowGuy object so you can distinguish them.
BTW... I wrote the code here without testing, but I think important parts are all here.
Related
I'm trying to draw a semi-transparent background and then opaque elements on top of it.
How come I can't do something like this?
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
this.Opacity = 0.5;
pe.Graphics.FillRectangle(trans_black_brush, square_rect_big);
this.Opacity = 1;
pe.Graphics.FillRectangle(solid_red_brush, square_rect);
}
I'd appreciate if someone with better understanding of Form drawing could tell me why this doesn't work :)
Update:
The solution has 3 forms:
1) Main (program, buttons etc)
2) Semi-transparent background (screen size, using opacity)
3) Transparent background but solid brushes on top.
In Form2's constructor, I have this:
Foreground = new FormForeground(this);
and in Form3's constructor I have this:
private Form_FormBackground m_Parent;
public FormForeground(FormBackground parent)
{
InitializeComponent();
FormBackground m_Parent = parent;
...
}
Whenever the mouse is clicked and used to draw with in form 3,
I update the parent's rectangle like so:
private void _UpdateParent()
{
m_Parent.s_DrawArea = m_DrawArea;
m_Parent.Invalidate();
}
The parent, form 2 then does its OnPaint() where it draws the marked area.
It does work, however the drawing does lag a bit compared to drawing directly in form3 (which does not produce the desired results because the drawn area needs to be transparent across the forms).
This doesn't work because Opacity is a Property of the Form and will always make the whole form and all its content have the current Value. It is perfect for fading a form in or out, though..
You can't achieve what you want with only one form.
Instead you will need two sychronized forms.
One can be somewhat opaque and will let the desktop shine through; the other must be transparent by making use of the TransparencyKey property and you can draw onto it..
To synchronize the two forms code the Move and the ResizeEnd events.
For a first setup use code like this:
A dummy form to create the semi-transparent look:
Form form0 = new Form() { Opacity = 0.33f , BackColor = Color.Black};
In the Form1's Load event:
TransparencyKey = Color.FromArgb(255, 147, 151, 162);
BackColor = TransparencyKey;
DoubleBuffered = true;
form0.Enabled = false;
form0.BringToFront();
form0.Show();
form0.Size = Size;
form0.Location = Location;
BringToFront();
And in the Move and the ResizeEnd events maybe code like this:
private void Form1_Move(object sender, EventArgs e)
{
form0.Size = Size;
form0.Location = Location;
}
private void Form1_ResizeEnd(object sender, EventArgs e)
{
form0.Size = Size;
form0.Location = Location;
}
You also may want to study this post that also shows a way to sandwich two forms.
Note that I picked a rather random color instead of the more common named color Fuchsia or any named colors. This is because I
Don't want to accidentally use it in the drawing, thius breaking making wrong spots transparent, but also
Don't want to make the form transparent for mouse actions, aka 'click-through'. This happens when using Fuchsia (and possibly some other colors) for some weird legacy reasons..
I have draggable images on my Windows Form. The PNG's themselves have transparent backgrounds yet it only matches the panel's background color when I load it. There are other labels with different colors I'd like to be able to see as I drag it instead. Anyone know what to use to make this happen?
http://postimg.org/image/d8p4s53pf/
EDIT:
Trying to make the PictureBox truely transparant. The drag stuff is done, but the background is just the background of the panel, and doesn't show controls it passes over.
I used this but it's a bit glitchy.
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//do nothing
}
protected override void OnMove(EventArgs e)
{
RecreateHandle();
}
Dragable Controls as such are not hard in WinForms. But once they need transparency the options are rather restricted: Each must be completely contained in its Parent; this implies that they all must be nested. No problem to create a set of transparent layers like you have in a graphics program.
But moving even one PictureBox-Pawn across a board full of others simply will not work with WinForms Controls.
But your aim is simple enough to do without any moving controls.
Instead you can simply draw the chess pieces onto the control surface in the Paint event. I have implemented a rudimentary solution and here is the Paint event from it:
List<ChessPiece> pieces = new List<ChessPiece>();
int mpIndex = -1; // index of the moving piece
Rectangle mmr; // rectangle where moving piece is drawn
// board display variables
int pieceSize = 60;
int tileSize = 80;
int borderWidth = 50;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
foreach(ChessPiece p in pieces)
{
if (!p.onBoard) continue; // skip the piece?
e.Graphics.DrawImage(imageList1.Images[p.pieceIndex],
borderWidth + p.col * tileSize,
borderWidth + p.row * tileSize);
}
// if we have a moving piece..
if (mpIndex >= 0 && !pieces[mpIndex].onBoard)
e.Graphics.DrawImage(imageList1.Images[pieces[mpIndex].pieceIndex],
mmr.Location);
}
As you can see it really isn't very long. It makes use of a few obvious variables and a few less obvious ones. The pieces list and the ImageList must be prepared up front. The rectangle mmr is set in the MouseMove:
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
mmr = new Rectangle(e.X - pieceSize / 2,
e.Y - pieceSize / 2, pieceSize, pieceSize);
pictureBox1.Invalidate(); // trigger the painting
}
}
I won't post the MouseUp and -Down events as they contain mostly code that doesn't actually pertain to moving transparent images but to managing the list of pieces..
The main idea is to draw all images from a list of pieces, unless a piece is not on the board. The moving piece is drawn separately, its coordinates are not from the board positions but from the mouse position.
If in the MouseUp event we find that the the move is illegal, we can simply set it back onBoard without changing the position and it will be drawn at its old place.
In the MouseDown we determine the piece clicked on, set its onBoard=false and set the moving index mpIndex.
The class for the pieces is not long or complicated either;
public class ChessPiece
{
public bool onBoard { get; set; } // is the piece standing on the board?
public int row { get; set; } // row
public int col { get; set; } // column
public char piecetype { get; set; } // a little simplistic..not used..
public char color { get; set;} // .. could be an enumeration!
public int pieceIndex { get; set; } // points into imageList with 12 images
public ChessPiece(char color, char type, int r, int c, int ind)
{ onBoard = true; piecetype = type; this.color = color;
row = r; col = c; pieceIndex = ind; }
}
All in all the full code is around 180 lines, uncommented but including 60 lines of setting up the pieces alone and without any chess logic..
Here are the first 3 lines of the code to create the pieces:
void makePieces()
{
ChessPiece
p = new ChessPiece('W', 'R', 7, 0, 8); pieces.Add(p);
p = new ChessPiece('W', 'N', 7, 1, 10); pieces.Add(p);
p = new ChessPiece('W', 'B', 7, 2, 9); pieces.Add(p);
..
So, moving a transparent Png graphic over other Png graphics and a board image is rather simple..
Here is a screenshot that shows a black bishop over a white knight:
I want to create a listView that shows users nicknames for a chat program. For that I created a new class that inherits from listViewItem.
What i want to do is, depending on the length of the nickname scale my font size.
I have read lots of articles about scaling but ALL of them depend on a graphics object and i have no clue how i get one of those ??? i tried it with a label and there it would be from the paint event but listView doesnt have such an event? so how do i scale this font ?
Q:
How do I get the right fontsize that the Nickname will fit into a specified rectangle ?
EDIT: Forgot to say I'm completly new to anything with grafic stuff i only used the Designer and set some properties.
You should set OwnerDraw property of the ListView to true, add draw item event handler like this:
listView1.DrawItem += listView1_DrawItem;
And here is a simple implementation of what you want so you can play with and tune it up:
void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
float emSize = e.Item.Font.Size;
Font font = new Font(e.Item.Font.FontFamily, emSize);
while(e.Graphics.MeasureString(e.Item.Text, e.Item.Font).Width>e.Item.Bounds.Width)
{
emSize--;
font = new Font(e.Item.Font.FontFamily, emSize);
e.Item.Font = font;
}
e.DrawText();
}
You see that you need to change the font size and measure the string you want to display so it fits in the cell completely. Presuming that if your current font size doesn't fit, you want to make it smaller.
I marked #Nikola answer right because it explained a lot but in my case i needed something way simpler and thanks to #TaW i also got the problem with the Graphics solved here my code snippet
public static Font getNewFont(Font origFont, string text, float maxWidth, Graphics g)
{
float emSize = origFont.Size;
Font font = origFont;
while (g.MeasureString(text, font).Width > maxWidth)
{
emSize--;
font = new Font(origFont.FontFamily, emSize);
}
return font;
}
I'm creating a control that inherits from a Windows.Forms.Panel and has a specific region onto which I want to draw an image.
This code draws the image over the region I want, but doesn't stretch it.
private void PaintPanel(Graphics _g)
{
_g.FillRegion(new SolidBrush(BorderColor), BorderRegion);
_g.FillRegion(new TextureBrush(ContentImage), ContentRegion);
regionNeedsRefresh = false;
}
This code draws the image over the rectangle I want, and stretches it to fit the rectangle, but it doesn't draw over the exact region I want:
private void PaintPanel(Graphics _g)
{
_g.FillRegion(new SolidBrush(BorderColor), BorderRegion);
_g.DrawImage(ContentImage, ContentRegion.GetBounds(_g));
regionNeedsRefresh = false;
}
So what I need is a bit of both solutions I'm guessing...
Any help would be much appreciated!
You can use Graphics.DrawImage, and simply set the Clip property of the Graphics object to the Region you want to draw in before and after the operation.
So i am attempting to make a MasterMind program as sort of exercise.
Field of 40 picture boxes (line of 4, 10 rows)
6 buttons (red, green, orange, yellow, blue, purple)
When i press one of these buttons (lets assume the red one) then a picture box turns red.
My question is how do i iterate trough all these picture boxes?
I can get it to work but only if i write :
And this is offcourse no way to write this, would take me countless of lines that contain basicly the same.
private void picRood_Click(object sender, EventArgs e)
{
UpdateDisplay();
pb1.BackColor = System.Drawing.Color.Red;
}
Press the red button -> first picture box turns red
Press the blue button -> second picture box turns blue
Press the orange button -> third picture box turns orange
And so on...
Ive had a previous similar program that simulates a traffic light, there i could assign a value to each color (red 0, orange 1, green 2).
Is something similar needed or how exactly do i adress all those picture boxes and make them correspond to the proper button.
Best Regards.
I wouldn't use controls, instead you can use a single PictureBox and handle the Paint event. This lets you draw inside that PictureBox so you can quickly handle all your boxes.
In code:
// define a class to help us manage our grid
public class GridItem {
public Rectangle Bounds {get; set;}
public Brush Fill {get; set;}
}
// somewhere in your initialization code ie: the form's constructor
public MyForm() {
// create your collection of grid items
gridItems = new List<GridItem>(4 * 10); // width * height
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 4; x++) {
gridItems.Add(new GridItem() {
Bounds = new Rectangle(x * boxWidth, y * boxHeight, boxWidth, boxHeight),
Fill = Brushes.Red // or whatever color you want
});
}
}
}
// make sure you've attached this to your pictureBox's Paint event
private void PictureBoxPaint(object sender, PaintEventArgs e) {
// paint all your grid items
foreach (GridItem item in gridItems) {
e.Graphics.FillRectangle(item.Fill, item.Bounds);
}
}
// now if you want to change the color of a box
private void OnClickBlue(object sender, EventArgs e) {
// if you need to set a certain box at row,column use:
// index = column + row * 4
gridItems[2].Fill = Brushes.Blue;
pictureBox.Invalidate(); // we need to repaint the picturebox
}
I would use a panel as the container control for all the pic boxes, then:
foreach (PictureBox pic in myPanel.Controls)
{
// do something to set a color
// buttons can set an enum representing a hex value for color maybe...???
}
I wouldn't use pictureboxes, but instead would use a single picturebox, drawing directly onto it using GDI. The result is a lot faster, and it will set you up to write more complex games involving sprites and animation ;)
It's very easy to learn how.