C #. Отображение и перемещение значков в форме окна - PullRequest
1 голос
/ 20 февраля 2010

Мне нужно отобразить набор значков в форме окна и перемещать их во время выполнения. Я использовал элемент управления PictureBox для отображения значков, но мне пришлось бы либо не менять picturebox.SizeMode на Stretched, что приводит к очень маленьким значкам, либо они будут выглядеть размытыми и ужасными во время выполнения, даже если они являются значками высокого качества. .

Я интенсивно гуглял, но решение оказалось бесполезным, хотя у многих людей была такая же проблема. У вас есть решение?

Если нет, то как бы ВЫ могли бы отображать значки в форме окна, чтобы их можно было легко перемещать во время выполнения?

Спасибо, что поделились своим временем и знаниями.

EDIT Вот несколько снимков экрана: Верхний - это PictureBox во время разработки, а нижний -

альтернативный текст http://www.imagechicken.com/uploads/1266687694012129500.png

альтернативный текст http://www.imagechicken.com/uploads/1266687487098617800.png

Ответы [ 4 ]

1 голос
/ 20 февраля 2010

Я бы использовал растровые изображения вместо иконок, как говорили другие. Вот как бы я это сделал:

Прежде всего, создайте класс, который содержит растровое изображение и делегат, который будет указывать на метод, который получит положение растрового изображения как функцию времени.

delegate Point PositionFunction(int time);

class MovingBitmap
{
    private Bitmap bitmap;
    private PositionFunction positionFunction;

    public MovingBitmap(Bitmap bitmap, PositionFunction positionFunction)
    {
        if (bitmap == null)
        {
            throw new ArgumentNullException("bitmap");
        }
        else if (positionFunction == null)
        {
            throw new ArgumentNullException("bitmap");
        }

        this.bitmap = bitmap;
        this.positionFunction = positionFunction;
    }

    public Bitmap Bitmap
    {
        get { return this.bitmap; }
    }

    public PositionFunction PositionFunction
    {
        get { return this.positionFunction; }
    }
}

Для функции положения вам нужно решить, как вы хотите перемещать растровые изображения. (Примечание: время выражается в миллисекундах.) Это может быть просто:

private Point SimpleTimeFunction(int time)
{
    return new Point(time / 5, time / 5);
}

private Point ParabolaFunction(int time)
{
    return new Point(time / 5, (time / 5) * (time / 5));
}

Или это может быть кусочная функция, составленная из нескольких уравнений, например:

if (time < 5000)
{
    return new Point(time / 5, 2 * (time / 5));
}
else
{
    return new Point(time / 5, time / 5) * time);
}

Все сводится к тому, как вы хотите, чтобы это двигалось. Надеюсь, вам нравится математика. :)

Затем в элемент управления, который будет содержать растровые изображения, добавьте поле List<MovingBitmap>.

private List<MovingBitmap> bitmaps = new List<MovingBitmap>();

Затем вам нужно растровое изображение размера родительского элемента управления, чтобы использовать его в качестве буфера, чтобы пользовательский интерфейс был без мерцания. Вы нарисуете все движущиеся растровые изображения в буфере, а затем в свою очередь нарисуете это растровое изображение на элементе управления в OnPaint.

private int startTime;  // set this to System.Environment.TickCount when you start

// Add this line to the constructor
this.UpdateBufferSize();

private void UpdateBufferSize()
{
    if (this.buffer != null)
    {
        this.buffer.Dispose();
    }

    this.buffer = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
}

private void RefreshBuffer()
{
    int timeElapsed = Environment.TickCount - this.startTime;

    using (Graphics g = Graphics.FromImage(this.buffer))
    {
        g.Clear(this.BackColor);

        foreach (MovingBitmap movingBitmap in this.bitmaps)
        {
            Rectangle destRectangle = new Rectangle(
                movingBitmap.PositionFunction(timeElapsed), 
                movingBitmap.Bitmap.Size);

            g.DrawImage(movingBitmap.Bitmap, destRectangle);
        }
    }
}

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    e.Graphics.DrawImage(this.buffer, Point.Empty);
}

Для достижения эффекта анимации вам понадобится таймер. Когда таймер истекает, обновите буфер, а затем элемент управления.

private System.Timers.Timer timer;
private ParameterlessVoid refreshMethod;
private delegate void ParameterlessVoid();

// Add these four lines to the constructor
this.timer = new System.Timers.Timer(1000 / 20);  // 20 times per second
this.timer.AutoReset = true;
this.timer.Elapsed += this.HandleTimerElapsed;
this.refreshMethod = new ParameterlessVoid(this.Refresh);

private void HandleTimerElapsed(object sender, EventArgs e)
{
    this.RefreshBuffer();
    this.Invoke(this.refreshMethod);
}

private void Start()
{
    this.startTime = System.Environment.TickCount;
    this.timer.Start();
}

Я думаю, что это в основном все, что вам нужно сделать. Это не полностью проверено и отлажено, но оно должно указать вам правильное направление.

0 голосов
/ 20 февраля 2010

Я делаю это с помощью набора иконок размером 32x32 .png. Я использую FlowLayoutPanel в качестве контейнера и добавляю к нему элементы управления PictureBox. В этом фрагменте uxIconPanel является FlowLayoutPanel.

foreach (Image img in GetImageListForClassification(entityClass))
{
    PictureBox box = new PictureBox();
    box.Image = img;
    box.Size = box.PreferredSize;
    box.Anchor = AnchorStyles.Top | AnchorStyles.Left;
    uxIconPanel.Controls.Add(box);
}
0 голосов
/ 20 февраля 2010

Начните с массива для хранения ваших классов изображений, которые будут нуждаться в

- image
- left
- top
- height
- width

Переопределите OnPaint () и нарисуйте каждое изображение в массиве в его месте.

Обработка события MouseDown.

- track the mouse down location
- determine whether the location hits one of the images 
  and track which one was hit
- track the original location of the hit image

Обработка события MouseMove.

- if not mouse button pressed then return
- if not tracking a hit from mouse down then return
- determine the change in position of the mouse from 
  what it was in the mouse down event
- apply the change in position to the original image position
  to set the new position of the tracked image
- Invalidate() to cause a repaint in the new position

Этот псевдокод даст базовое перетаскивание объекта.

0 голосов
/ 20 февраля 2010

Переопределите OnPaint() и нарисуйте значки с помощью e.Graphics.DrawImageUnscaled (), где вы хотите их.

...