用C#模拟雷达最好的方法是什么?
我有一个图片框在我的表格中的一个分组框中,背景图片是雷达的图片。我的目的是在运行时在雷达区域(覆盖)内动态加载微小的Jpeg图像,但我不确定实现这一点的最佳方法。 所有疯狂的想法都受到欢迎(但我更喜欢理智、容易实现的想法)。用C#模拟雷达最好的方法是什么?,c#,.net,winforms,graphics,C#,.net,Winforms,Graphics,我有一个图片框在我的表格中的一个分组框中,背景图片是雷达的图片。我的目的是在运行时在雷达区域(覆盖)内动态加载微小的Jpeg图像,但我不确定实现这一点的最佳方法。 所有疯狂的想法都受到欢迎(但我更喜欢理智、容易实现的想法)。 谢谢大家。这在很大程度上取决于“雷达”的外观,但几乎可以肯定的是,您需要实现绘制事件处理程序,并自己绘制雷达显示的内容。一个图片框只能让你走到这一步(“不太可能”) GDI+非常容易用于绘制圆、线、文本和图像,并可让您完全控制显示器的外观。最简单的方法是将微型JPEG加载到
谢谢大家。这在很大程度上取决于“雷达”的外观,但几乎可以肯定的是,您需要实现绘制事件处理程序,并自己绘制雷达显示的内容。一个图片框只能让你走到这一步(“不太可能”)
GDI+非常容易用于绘制圆、线、文本和图像,并可让您完全控制显示器的外观。最简单的方法是将微型JPEG加载到微型PictureBox中,并在运行时将其添加到主PictureBox的控件集合中(即将其放在PictureBox上) 因为这可能会产生闪烁,所以稍微复杂一点的方法是将主图片和小图片保留在类级位图对象中,并且在主PictureBox的Paint事件中,将主图片和每个小图片复制到第二个类级位图(名为_doubleBuffer或类似的东西)上使用DrawImage方法,然后将_doubleBuffer复制到PictureBox(也使用DrawImage)。每当需要更新显示并重新绘制所有内容时,只需调用PictureBox的Invalidate方法 这里有大量的例子来说明如何使用这些方法。祝你好运,听起来很有趣(如果你正在改写经典的街机游戏《潜水艇》,请告诉我-我喜欢这个游戏)。例如:
// Among others
using System.Collections.Generic;
using System.Drawing;
using System.IO;
class TinyPic {
public readonly Image Picture;
public readonly Rectangle Bounds;
public TinyPic(Image picture, int x, int y) {
Picture = picture;
Bounds = new Rectangle(x, y, picture.Width, picture.Height);
}
}
class MyForm : Form {
Dictionary<String, TinyPic> tinyPics = new Dictionary<String, TinyPic>();
public MyForm(){
InitializeComponent(); // assuming Panel myRadarBox
// with your background is there somewhere;
myRadarBox.Paint += new PaintEventHandler(OnPaintRadar);
}
void OnPaintRadar(Object sender, PaintEventArgs e){
foreach(var item in tinyPics){
TinyPic tp = item.Value;
e.Graphics.DrawImageUnscaled(tp.Picture, tp.Bounds.Location);
}
}
void AddPic(String path, int x, int y){
if ( File.Exists(path) ){
var tp = new TinyPic(Image.FromFile(path), x, y);
tinyPics[path] = tp;
myRadarBox.Invalidate(tp.Bounds);
}
}
void RemovePic(String path){
TinyPic tp;
if ( tinyPics.TryGetValue(path, out tp) ){
tinyPics.Remove(path);
tp.Picture.Dispose();
myRadarBox.Invalidate(tp.Bounds);
}
}
}
//等等
使用System.Collections.Generic;
使用系统图;
使用System.IO;
TinyPic类{
公众只读图片;
公共只读矩形边界;
公共TinyPic(图像图片,整数x,整数y){
图片=图片;
边界=新矩形(x,y,picture.Width,picture.Height);
}
}
类MyForm:Form{
Dictionary tinyPics=新字典();
公共MyForm(){
InitializeComponent();//假设面板为myRadarBox
//有你的背景在某处;
myRadarBox.Paint+=新的PaintEventHandler(OnPaintRadar);
}
PaintRadar无效(对象发送器,PaintEventArgs e){
foreach(tinyPics中的var项目){
t典型tp=项目价值;
e、 Graphics.DrawImageUnscaled(tp.Picture,tp.Bounds.Location);
}
}
void AddPic(字符串路径,整数x,整数y){
if(File.Exists(path)){
var tp=新的TinyPic(Image.FromFile(path),x,y);
tinyPics[path]=tp;
myRadarBox.Invalidate(tp.Bounds);
}
}
void RemovePic(字符串路径){
非典型tp;
if(tinyPics.TryGetValue(路径,输出tp)){
tinyPics.Remove(路径);
tp.Picture.Dispose();
myRadarBox.Invalidate(tp.Bounds);
}
}
}
这当然是非常基本的,假设图像源是路径,不需要处理许多复杂的事情,但这是一个快速而肮脏的jist,您当然可以在此基础上进行构建。运行一个示例应用程序,演示如何使用雷达的基础知识(或者至少是一种方法)。注意:此应用程序不会对微小图像进行双重缓冲或透明处理
该项目的源代码是
更新代码:
public partial class Form1 : Form
{
private Bitmap _canvas;
private float _sweepStartAngle = -90;
private float _sweepAngle = 15;
private SolidBrush _sweepBrush = new SolidBrush(Color.Red);
private Rectangle _sweepRect;
private Timer _sweepTimer = new Timer();
private Bitmap _submarine;
private Point _submarinePosition = new Point(0, 0);
private Random rnd = new Random();
public Form1()
{
InitializeComponent();
_canvas = new Bitmap(pbScope.Width, pbScope.Height);
pbScope.Image = _canvas;
_sweepRect = new Rectangle(0, 0, pbScope.Width, pbScope.Height);
_submarine = (Bitmap)pbSubmarine.Image;
RedrawScope();
_sweepTimer.Interval = 100;
_sweepTimer.Tick += new EventHandler(_sweepTimer_Tick);
_sweepTimer.Start();
}
void _sweepTimer_Tick(object sender, EventArgs e)
{
_sweepStartAngle += _sweepAngle;
RedrawScope();
}
private void RedrawScope()
{
using (Graphics g = Graphics.FromImage(_canvas))
{
// draw the background
g.DrawImage(pbBackground.Image, 0, 0);
// draw the "sweep"
GraphicsPath piepath = new GraphicsPath();
piepath.AddPie(_sweepRect, _sweepStartAngle, _sweepAngle);
g.FillPath(_sweepBrush, piepath);
//g.FillPie(_sweepBrush, _sweepRect, _sweepStartAngle, _sweepAngle);
// move the submarine and draw it
_submarinePosition.X += rnd.Next(3);
_submarinePosition.Y += rnd.Next(3);
// check if submarine intersects with piepath
Rectangle rect = new Rectangle(_submarinePosition, _submarine.Size);
Region region = new Region(piepath);
region.Intersect(rect);
if (!region.IsEmpty(g))
{
g.DrawImage(_submarine, _submarinePosition);
}
}
pbScope.Image = _canvas;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_sweepTimer.Stop();
_sweepTimer.Dispose();
}
private void Form1_Load(object sender, EventArgs e)
{
//GraphicsPath piepath = new GraphicsPath();
//piepath.AddPie(
}
}
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.pbScope = new System.Windows.Forms.PictureBox();
this.pbBackground = new System.Windows.Forms.PictureBox();
this.pbSubmarine = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pbScope)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pbBackground)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pbSubmarine)).BeginInit();
this.SuspendLayout();
//
// pbScope
//
this.pbScope.Location = new System.Drawing.Point(12, 12);
this.pbScope.Name = "pbScope";
this.pbScope.Size = new System.Drawing.Size(300, 300);
this.pbScope.TabIndex = 0;
this.pbScope.TabStop = false;
//
// pbBackground
//
this.pbBackground.Image = ((System.Drawing.Image)(resources.GetObject("pbBackground.Image")));
this.pbBackground.Location = new System.Drawing.Point(341, 12);
this.pbBackground.Name = "pbBackground";
this.pbBackground.Size = new System.Drawing.Size(300, 300);
this.pbBackground.TabIndex = 1;
this.pbBackground.TabStop = false;
this.pbBackground.Visible = false;
//
// pbSubmarine
//
this.pbSubmarine.Image = ((System.Drawing.Image)(resources.GetObject("pbSubmarine.Image")));
this.pbSubmarine.Location = new System.Drawing.Point(658, 45);
this.pbSubmarine.Name = "pbSubmarine";
this.pbSubmarine.Size = new System.Drawing.Size(48, 48);
this.pbSubmarine.TabIndex = 2;
this.pbSubmarine.TabStop = false;
this.pbSubmarine.Visible = false;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(326, 328);
this.Controls.Add(this.pbSubmarine);
this.Controls.Add(this.pbBackground);
this.Controls.Add(this.pbScope);
this.Name = "Form1";
this.Text = "Radar";
this.Load += new System.EventHandler(this.Form1_Load);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
((System.ComponentModel.ISupportInitialize)(this.pbScope)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pbBackground)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pbSubmarine)).EndInit();
this.ResumeLayout(false);
}
该死听起来很复杂。。。我想我会像上面JW建议的那样,为初学者阅读GDI+。谢谢你。没有玩潜艇;我更倾向于NES版的《红色十月的狩猎》。它并不复杂,实际上只是对杰森答案的详细阐述。我还谈到了GDI+和处理绘制事件。双缓冲部分对于避免闪烁是必不可少的。当雷达图像设置为我的主picturebox的背景图像时,为什么我需要双缓冲。我正在考虑在绘图区域中绘制一个容器(本例中为面板),使其不可见,然后创建一个rectf并将其边界设置为容器,并在rectf对象边界内绘制。。。你觉得那个场景怎么样?你会被忽悠的-相信我。它是复杂的,但是闪烁基本上来自GDI+绘图操作,在监视器刷新的中间(与其他问题一起)被“捕获”。避免这种情况的唯一方法是在不可见的画布上执行所有复杂的多步骤绘制操作,然后立即将此画布渲染到可见曲面。干杯。。。。。在C#中没有完成GDI+或任何图形编程,最后期限迫在眉睫(这是我突然想到的,你能在代码中编辑吗?今天的标准要求的不仅仅是外部链接。当然,尽管发布依赖于控件初始化和布局等的代码并不太实际。