깜박이는 C # winforms를 중지하는 방법
본질적으로 페인트 응용 프로그램과 같은 프로그램이 있습니다. 그러나 내 프로그램에는 몇 가지 깜박임 문제가 있습니다. 내 코드에 다음 줄이 있습니다 (깜박임을 제거해야하지만 그렇지 않습니다).
this.SetStyle(ControlStyles.AllPaintingInWmPaint
| ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
내 코드 (모양에 대한 슈퍼 및 하위 클래스 제외)는 다음과 같습니다.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Paint
{
public partial class Paint : Form
{
private Point startPoint;
private Point endPoint;
private Rectangle rect = new Rectangle();
private Int32 brushThickness = 0;
private Boolean drawSPaint = false;
private List<Shapes> listOfShapes = new List<Shapes>();
private Color currentColor;
private Color currentBoarderColor;
private Boolean IsShapeRectangle = false;
private Boolean IsShapeCircle = false;
private Boolean IsShapeLine = false;
public SPaint()
{
InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
currentColor = Color.Red;
currentBoarderColor = Color.DodgerBlue;
IsShapeRectangle = true;
}
private void panelArea_Paint(object sender, PaintEventArgs e)
{
Graphics g = panelArea.CreateGraphics();
if (drawSPaint == true)
{
Pen p = new Pen(Color.Blue);
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
if (IsShapeRectangle == true)
{
g.DrawRectangle(p, rect);
}
else if (IsShapeCircle == true)
{
g.DrawEllipse(p, rect);
}
else if (IsShapeLine == true)
{
g.DrawLine(p, startPoint, endPoint);
}
}
foreach (Shapes shape in listOfShapes)
{
shape.Draw(g);
}
}
private void panelArea_MouseDown(object sender, MouseEventArgs e)
{
startPoint.X = e.X;
startPoint.Y = e.Y;
drawSPaint = true;
}
private void panelArea_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
if (e.X > startPoint.X)
{
rect.X = startPoint.X;
rect.Width = e.X - startPoint.X;
}
else
{
rect.X = e.X;
rect.Width = startPoint.X - e.X;
}
if (e.Y > startPoint.Y)
{
rect.Y = startPoint.Y;
rect.Height = e.Y - startPoint.Y;
}
else
{
rect.Y = e.Y;
rect.Height = startPoint.Y - e.Y;
}
panelArea.Invalidate();
}
}
private void panelArea_MouseUp(object sender, MouseEventArgs e)
{
endPoint.X = e.X;
endPoint.Y = e.Y;
drawSPaint = false;
if (rect.Width > 0 && rect.Height > 0)
{
if (IsShapeRectangle == true)
{
listOfShapes.Add(new TheRectangles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeCircle == true)
{
listOfShapes.Add(new TheCircles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeLine == true)
{
listOfShapes.Add(new TheLines(startPoint, endPoint, currentColor, currentBoarderColor, brushThickness));
}
panelArea.Invalidate();
}
}
private void rectangleToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeRectangle = true;
IsShapeCircle = false;
IsShapeLine = false;
}
private void ellipseToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeRectangle = false;
IsShapeCircle = true;
IsShapeLine = false;
}
private void lineToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeCircle = false;
IsShapeRectangle = false;
IsShapeLine = true;
}
private void ThicknessLevel0_Click(object sender, EventArgs e)
{
brushThickness = 0;
}
private void ThicknessLevel2_Click(object sender, EventArgs e)
{
brushThickness = 2;
}
private void ThicknessLevel4_Click(object sender, EventArgs e)
{
brushThickness = 4;
}
private void ThicknessLevel6_Click(object sender, EventArgs e)
{
brushThickness = 6;
}
private void ThicknessLevel8_Click(object sender, EventArgs e)
{
brushThickness = 8;
}
private void ThicknessLevel10_Click(object sender, EventArgs e)
{
brushThickness = 10;
}
private void ThicknessLevel12_Click(object sender, EventArgs e)
{
brushThickness = 12;
}
private void ThicknessLevel14_Click(object sender, EventArgs e)
{
brushThickness = 14;
}
private void FillColour_Click(object sender, EventArgs e)
{
ColorDialog fillColourDialog = new ColorDialog();
fillColourDialog.ShowDialog();
currentColor = fillColourDialog.Color;
panelArea.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
ColorDialog fillColourDialog = new ColorDialog();
fillColourDialog.ShowDialog();
currentBoarderColor = fillColourDialog.Color;
panelArea.Invalidate();
}
}
}
깜박임을 어떻게 중지합니까?
* 업데이트 : *이 코드는 실제로 양식에 직접 그릴 때 잘 작동합니다. 하지만 패널에 그리려고하면 깜박임이 문제가됩니다
"깨끗한 솔루션"의 경우 기본 패널을 계속 사용하려면 리플렉션을 사용하여 이중 버퍼링을 구현할 수 있습니다.이 코드를 그리려는 패널이있는 양식에 추가하면됩니다.
typeof(Panel).InvokeMember("DoubleBuffered",
BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, DrawingPanel, new object[] { true });
여기서 "DrawingPanel"은 이중 버퍼링을 수행 할 패널의 이름입니다.
질문을받은 이후로 많은 시간이 지났음을 알고 있지만 이것은 미래에 누군가에게 도움이 될 수 있습니다.
마침내 깜박임을 해결했습니다. 양식 대신 패널에 그림을 그렸기 때문에 아래 코드 줄은 깜박임을 해결하지 못합니다.
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,
true);
SetStyle은 'YourProject.YourProject'(또는 그로부터 파생 된) 유형이어야합니다. 따라서 SPaint.SPaint에서 파생되는 MyPanel을 사용하여 직접 이중 버퍼링을 사용할 수 있도록 클래스를 만들어야합니다. 패널-양식이 아니라) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SPaint;
namespace YourProject
{
public class MyPanel : System.Windows.Forms.Panel
{
public MyPanel()
{
this.SetStyle(
System.Windows.Forms.ControlStyles.UserPaint |
System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer,
true);
}
}
}
이 작업을 수행 한 후에는 (당신이하는 일을 진정으로 알지 못하는 한 디자이너 코드를 편집해서는 안되지만) Form.Designer.cs를 편집해야합니다. 이 파일 안에는 다음과 같은 코드가 있습니다.
this.panelArea = new YourProject.MyPanel();
위의 줄을 다음과 같이 변경해야합니다.
this.panelArea = new MyPanel();
이 단계를 완료하면 페인트 프로그램이 더 이상 깜박이지 않습니다.
같은 문제를 가진 다른 사람에게는 문제가 마침내 해결됩니다.
즐겨!
이것을 복사하여 프로젝트에 붙여 넣으십시오.
protected override CreateParams CreateParams
{
get
{
CreateParams handleParam = base.CreateParams;
handleParam.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return handleParam;
}
}
이렇게하면 폼 수준에서 모든 컨트롤에 대해 이중 버퍼링이 가능합니다. 그렇지 않으면 각 컨트롤에 대해 이중 버퍼링을 개별적으로 활성화해야합니다. 블랭킷 이중 버퍼링이 원하지 않는 부작용을 줄 수 있기 때문에 이중 버퍼링을 미세 조정하는 것이 좋습니다.
나는 같은 문제가 있었다. 나는 플리커를 100 % 제거 할 수 없었지만 (포인트 2 참조) 이것을 사용했습니다.
protected override void OnPaint(PaintEventArgs e) {}
만큼 잘
this.DoubleBuffered = true;
깜박임의 주요 문제는
- 그것을 올바른 순서로 칠하십시오!
- 그리기 기능이 약 1/60 초 미만인지 확인하십시오.
winforms는 OnPaint
양식을 다시 그려야 할 때마다 메서드를 호출합니다 . 마우스 커서를 양식 위로 이동하면 때때로 다시 그리기 이벤트를 호출하는 등 여러 가지 방법으로 유효성을 검사 할 수 있습니다.
에 대한 중요한 참고 사항은 OnPaint
매번 처음부터 시작하는 것이 아니라 원래 있던 곳에서 시작한다는 것입니다. 배경색을 가득 채우면 깜박일 가능성이 높습니다.
마지막으로 gfx 객체. 내부 OnPaint
에서 그래픽 객체를 다시 만들어야하지만 화면 크기가 변경된 경우에만 가능합니다. 개체를 다시 만드는 것은 비용이 많이 들고 다시 만들기 전에 폐기해야합니다 (가비지 수집은 100 % 올바르게 처리하지 않거나 문서에 나와 있음). 클래스 변수를 만들었습니다.
protected Graphics gfx = null;
그런 다음 로컬에서 OnPaint
그렇게 사용 했지만 이것은 수업의 다른 위치에서 gfx 객체를 사용해야했기 때문입니다. 그렇지 않으면 이것을하지 마십시오. OnPaint로만 그림을 그리는 경우 e.Graphics
!!
// clean up old graphics object
gfx.Dispose();
// recreate graphics object (dont use e.Graphics, because we need to use it
// in other functions)
gfx = this.CreateGraphics();
도움이 되었기를 바랍니다.
이중 버퍼링은 여기서 큰 도움이되지 않을 것입니다. 나는 얼마 전에 이것을 만났고 다소 서투른 방식으로 별도의 패널을 추가했지만 내 응용 프로그램에서는 작동했습니다.
가지고있는 원본 패널 (panelArea)을 투명한 영역으로 만들고이를 두 번째 패널 (예를 들어 panelDraw라고 부르는 패널) 위에 놓습니다. panelArea가 앞에 있는지 확인하십시오. 나는 이것을 채찍질하고 깜박임을 제거했지만 그려지는 모양이 번져서 완전한 해결책이 아닙니다.
투명 패널은 원본 패널에서 일부 페인트 작업을 재정 의하여 만들 수 있습니다.
public class ClearPanel : Panel
{
public ClearPanel(){}
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020;
return createParams;
}
}
protected override void OnPaintBackground(PaintEventArgs e){}
}
아이디어는 'panelArea'의 MouseMove 이벤트 동안 임시 모양 그리기를 처리하고 MouseUp 이벤트에서 'panelDraw'만 다시 그리는 것입니다.
// Use the panelDraw paint event to draw shapes that are done
void panelDraw_Paint(object sender, PaintEventArgs e)
{
Graphics g = panelDraw.CreateGraphics();
foreach (Rectangle shape in listOfShapes)
{
shape.Draw(g);
}
}
// Use the panelArea_paint event to update the new shape-dragging...
private void panelArea_Paint(object sender, PaintEventArgs e)
{
Graphics g = panelArea.CreateGraphics();
if (drawSETPaint == true)
{
Pen p = new Pen(Color.Blue);
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
if (IsShapeRectangle == true)
{
g.DrawRectangle(p, rect);
}
else if (IsShapeCircle == true)
{
g.DrawEllipse(p, rect);
}
else if (IsShapeLine == true)
{
g.DrawLine(p, startPoint, endPoint);
}
}
}
private void panelArea_MouseUp(object sender, MouseEventArgs e)
{
endPoint.X = e.X;
endPoint.Y = e.Y;
drawSETPaint = false;
if (rect.Width > 0 && rect.Height > 0)
{
if (IsShapeRectangle == true)
{
listOfShapes.Add(new TheRectangles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeCircle == true)
{
listOfShapes.Add(new TheCircles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeLine == true)
{
listOfShapes.Add(new TheLines(startPoint, endPoint, currentColor, currentBoarderColor, brushThickness));
}
panelArea.Invalidate();
}
panelDraw.Invalidate();
}
나는 이것이 정말 오래된 질문이라는 것을 알고 있지만 누군가가 유용하다고 생각할 것입니다.
바이퍼의 대답을 조금만 개선하고 싶습니다.
Panel 클래스를 간단하게 확장하고 리플렉션을 통해 설정 속성을 숨길 수 있습니다.
public static class MyExtensions {
public static void SetDoubleBuffered(this Panel panel) {
typeof(Panel).InvokeMember(
"DoubleBuffered",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
null,
panel,
new object[] { true });
}
}
패널 변수의 이름이 myPanel
이면 myPanel.SetDoubleBuffered ();
그리고 그게 다야. 코드가 훨씬 깔끔해 보입니다.
OnPaintBackground를 재정의하고 배경 지우기를 직접 처리하는 것이 좋습니다. 전체 컨트롤을 그리는 것을 알고 있다면 OnPaintBackground에서 아무것도 할 수 없으며 (기본 메서드를 호출하지 마십시오) 배경색이 먼저 그려지는 것을 방지합니다.
이 상태에서는 이중 버퍼를 활성화해야합니다. 현재 양식을 열고 양식 속성으로 이동하여 이중 버퍼 적용 true; 또는이 코드를 작성할 수도 있습니다.
this.DoubleBuffered = true;
양식로드 중.
다음은 깜빡이지 않는 .net에서 원을 움직이는 프로그램입니다.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
namespace CircleMove
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
int x=0,y=0;
Thread t;
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
void MainFormPaint(object sender, PaintEventArgs e)
{
Graphics g=e.Graphics;
Pen p=new Pen(Color.Orange);
Brush b=new SolidBrush(Color.Red);
// g.FillRectangle(b,0,0,100,100);
g.FillEllipse(b,x,y,100,100);
}
void MainFormLoad(object sender, EventArgs e)
{
t=new Thread( new ThreadStart(
()=>{
while(true)
{
Thread.Sleep(10);
x++;y++;
this.Invoke(new Action(
()=>{
this.Refresh();
this.Invalidate();
this.DoubleBuffered=true;
}
)
);
}
}
)
);
t.Start();
}
}
}
위의 모든 방법이 작동하지 않으면 언제든지 Microsoft 자습서에 대한 자체 이중 버퍼 링크를 만들 수 있습니다. https://docs.microsoft.com/en-us/dotnet/framework/winforms/advanced/how-to-reduce- 양식 및 제어를위한 이중 버퍼링으로 그래픽 깜박임
당신을 위해 작동하길 바랍니다
메모리가 부족한 경우 (따라서 이중 버퍼링의 메모리 비용이 필요하지 않음) 깜박임을 제거하지는 않지만 줄일 수있는 한 가지 방법은 배경색을 현재 장면에서 지배적 인 색상으로 설정하는 것입니다.
Why this helps: flicker is a momentary flash of the background color, which the OS draws before drawing child controls or your custom drawing code. If that flash is a color that is closer to the final color to be displayed, it will be less noticeable.
If you are not sure what color to start with, start with 50% gray, because this is an average of black and white, so will be closer to most colors in your scene.
myFormOrControl.BackColor = Color.Gray;
Try to insert drawing logic in current form's
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
}
method. In this case you should use parameter e to get Graphics object. Use e.Graphics property. Then you should invoke Invalidate() method for this form whenever form must be redrawn. PS: DoubleBuffered must be set to true.
just do this.Refresh()
when shown the form.
Can you try using a timer and boolean to check if mouse is down, and paint in that spot, using a variable again check if user has moved his mouse, if moved paint that spot too etc.
Or just check if mouse down(via boolean that sets true when mouse is down) using a timer and paint it considering you are probably trying to just paint one pixel, not like you have shadow etc. Instead of using actual mousedown. So you check every 1 second instead of 0.0001 and it wont flicker. Or vice-versa, try it with your own times.
참고URL : https://stackoverflow.com/questions/8046560/how-to-stop-flickering-c-sharp-winforms
'IT박스' 카테고리의 다른 글
JPEG의 품질 수준을 알 수 있습니까? (0) | 2020.11.23 |
---|---|
파이썬에서 문자열 내에서 여러 문자열 찾기 (0) | 2020.11.23 |
녹아웃보기 모델에 대한 변경 감지 (0) | 2020.11.23 |
preg_replace를 사용하여 영숫자가 아닌 모든 문자 제거 (0) | 2020.11.23 |
Django 템플릿에 이미지 파일을 어떻게 포함하나요? (0) | 2020.11.23 |