Рисование собственного фона родительских и родительских детей в C#
Я пытаюсь использовать этот учебник, чтобы у меня была прозрачная кнопка. Он отлично работает для основного фона, но не отрисовывает других детей. Если я использую BringToFront()
тогда у него нет рисунка другого ребенка, где он должен быть.
Я начал обойти это, добавив это в код:
foreach (Control child in Parent.Controls) {
if(child != this) {
InvokePaintBackground(child, pea);
InvokePaint(child, pea);
}
}
И хотя я получаю кое -что из того, что хочу, оно находится не в том месте (слева, а не посередине, где должно быть), и фигуры, нарисованные в событии рисования ребенка, также не отображаются.
Как я могу изменить так, чтобы у меня были все другие дети, дающие полную иллюзию прозрачности?
Примечание: я не беспокоюсь о том, чтобы причинять боль кому-либо, кроме других детей, так как знаю, что их нет, и есть множество других мест, где можно узнать, как рекурсивно получить всех детей.
Благодаря ответу C.Evenhuis, теперь он работает. Моя реализация проста (только один дочерний элемент), так что это мой код. Для будущих читателей обязательно прочитайте этот пост, чтобы получить полный охват.
using (PaintEventArgs pea = new PaintEventArgs(e.Graphics, rect)) {
pea.Graphics.SetClip(rect);
InvokePaintBackground(Parent, pea);
InvokePaint(Parent, pea);
foreach (Control child in Parent.Controls) {
if (child != this) {
pea.Graphics.ResetTransform();
pea.Graphics.TranslateTransform(child.Left - Left, child.Top - Top);
InvokePaintBackground(child, pea);
InvokePaint(child, pea);
}
}
}
2 ответа
При рисовании все элементы управления предполагают, что их верхний левый угол находится в координате (0, 0). Это достигается установкой окна просмотра Graphics
объект до координат управления перед OnPaint
называется.
Чтобы нарисовать другие элементы управления, вам придется сделать это вручную:
if (child != this)
{
int offsetX = control.Left - Left;
int offsetY = control.Top - Top;
// Set the viewport to that of the control
pevent.Graphics.TranslateTransform(offsetX, offsetY);
// Translate the clip rectangle to the new coordinate base
Rectangle clip = pevent.ClipRectangle;
clip.Offset(-offsetX, -offsetY); // Ugly self-modifying struct
PaintEventArgs clippedArgs = new PaintEventArgs(pevent.Graphics, clip);
InvokePaintBackground(control, clippedArgs);
InvokePaint(control, clippedArgs);
pevent.Graphics.TranslateTransform(-offsetX, -offsetY)
}
Все становится немного сложнее, если основной элемент управления Panel
содержит собственные дочерние элементы управления - они не отображаются автоматически вместе с их родителями. Если вам нужно поддержать это, я предлагаю отправить WM_PRINT
сообщение родительскому элементу управления и элементам управления silbing под текущим элементом управления - для элементов управления одного уровня вы можете затем установить PRF_CHILDREN
флаг, чтобы позволить ему рисовать своих потомков тоже.
Также в настоящее время вы рисуете все элементы управления родного брата - в том числе выше текущего элемента управления. Вы могли бы хотеть позволить петле идти назад и break
когда вы достигнете текущего контроля. Это не будет реальной проблемой, пока вы не начнете укладывать несколько прозрачных элементов управления.
Это не ответ, но однажды мне пришлось сделать что-то подобное. Вот что я сделал:
this.SetStyle(
ControlStyles.ResizeRedraw |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.UserPaint, true);
this.BackColor = Color.Transparent;
protected override void OnPaint(PaintEventArgs e)
{
// TODO: Draw the button here
base.OnPaint(e);
}
Это не привлекает детей, но работает лучше, чем InvokePaintBackground
а также InvokePaint
по какой-то причине. У меня было много неприятностей, когда я пытался нарисовать детей, особенно когда дети были владельцами, которых управлял сторонний контроль (я говорю действительно странные вопросы). Я задам вопрос, чтобы увидеть, есть ли другие идеи. Удачи.