Как переместить окно R Tk на экран родительского процесса?

1

Я создаю процесс R из приложения С#, а запускаемый R-скрипт создает окно Tk. Сейчас окно всегда отображается на основном мониторе, а мое приложение С# работает на втором мониторе. Как переместить его на 2-й монитор (когда есть родительский процесс) или заставить его создать там в первую очередь?

Вот как я запускаю процесс прямо сейчас:

 var process = new System.Diagnostics.Process
 {
     StartInfo = new ProcessStartInfo(rFilepath, String.Format("\"{0}\"", scriptFilepath))
 };
 process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
 process.StartInfo.CreateNoWindow = true;
 process.StartInfo.UseShellExecute = false;
 process.StartInfo.RedirectStandardOutput = process.StartInfo.RedirectStandardError = true;
 process.Start();
 process.EnableRaisingEvents = true;
 process.Exited += (x, y) =>
 {
      if (process.ExitCode != 0)
          Program.HandleException(new Exception(String.Format("Output:\r\n{0}\r\n\r\nError:\r\n{1}",
                                                process.StandardOutput.ReadToEnd(),
                                                process.StandardError.ReadToEnd())));
 };

Здесь часть скрипта R, которая устанавливает основное окно:

base <- tktoplevel()
tkwm.title(base, "AppName")

// create frames and controls here and put them in with tkgrid

tcl("wm", "attributes", base, topmost=TRUE)
tcl("wm", "attributes", base, topmost=FALSE)
tkfocus(base)
  • 0
    Я думаю, что это зависит от ОС, если это вообще возможно. Какая у тебя ОС? Окна?
  • 0
    Да винда. Я надеюсь избежать вызовов Win32, таких как SetWindowPosition, если это возможно.
Показать ещё 1 комментарий
Теги:
tk

1 ответ

1
Лучший ответ

Я не эксперт R, но поскольку ответов на ваш вопрос нет, я попробую.

Здесь следует общий код, который может перемещать главное окно дочернего процесса с С#. Так как он использует функцию WinAPI SetWindowPos, здесь использовался P/Invoke.

Импорт из SetWindowPosFlags немного страшен, но это только версия С# исходных заголовков, задокументированных в Windows API.

Код ниже перемещает окно X +10 и Y +10 относительно вашего родительского процесса. Вы можете изменить X и Y, чтобы отразить ваши фактические потребности.

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;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsPosTests
{
[Flags()]
enum SetWindowPosFlags : uint
{
    /// <summary>If the calling thread and the thread that owns the window are attached to different input queues, 
    /// the system posts the request to the thread that owns the window. This prevents the calling thread from 
    /// blocking its execution while other threads process the request.</summary>
    /// <remarks>SWP_ASYNCWINDOWPOS</remarks>
    AsynchronousWindowPosition = 0x4000,
    /// <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
    /// <remarks>SWP_DEFERERASE</remarks>
    DeferErase = 0x2000,
    /// <summary>Draws a frame (defined in the window class description) around the window.</summary>
    /// <remarks>SWP_DRAWFRAME</remarks>
    DrawFrame = 0x0020,
    /// <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to 
    /// the window, even if the window size is not being changed. If this flag is not specified, WM_NCCALCSIZE 
    /// is sent only when the window size is being changed.</summary>
    /// <remarks>SWP_FRAMECHANGED</remarks>
    FrameChanged = 0x0020,
    /// <summary>Hides the window.</summary>
    /// <remarks>SWP_HIDEWINDOW</remarks>
    HideWindow = 0x0080,
    /// <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the 
    /// top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter 
    /// parameter).</summary>
    /// <remarks>SWP_NOACTIVATE</remarks>
    DoNotActivate = 0x0010,
    /// <summary>Discards the entire contents of the client area. If this flag is not specified, the valid 
    /// contents of the client area are saved and copied back into the client area after the window is sized or 
    /// repositioned.</summary>
    /// <remarks>SWP_NOCOPYBITS</remarks>
    DoNotCopyBits = 0x0100,
    /// <summary>Retains the current position (ignores X and Y parameters).</summary>
    /// <remarks>SWP_NOMOVE</remarks>
    IgnoreMove = 0x0002,
    /// <summary>Does not change the owner window position in the Z order.</summary>
    /// <remarks>SWP_NOOWNERZORDER</remarks>
    DoNotChangeOwnerZOrder = 0x0200,
    /// <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to 
    /// the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent 
    /// window uncovered as a result of the window being moved. When this flag is set, the application must 
    /// explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
    /// <remarks>SWP_NOREDRAW</remarks>
    DoNotRedraw = 0x0008,
    /// <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
    /// <remarks>SWP_NOREPOSITION</remarks>
    DoNotReposition = 0x0200,
    /// <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
    /// <remarks>SWP_NOSENDCHANGING</remarks>
    DoNotSendChangingEvent = 0x0400,
    /// <summary>Retains the current size (ignores the cx and cy parameters).</summary>
    /// <remarks>SWP_NOSIZE</remarks>
    IgnoreResize = 0x0001,
    /// <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
    /// <remarks>SWP_NOZORDER</remarks>
    IgnoreZOrder = 0x0004,
    /// <summary>Displays the window.</summary>
    /// <remarks>SWP_SHOWWINDOW</remarks>
    ShowWindow = 0x0040,
}

public partial class Form1 : Form
{
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);

    public Form1()
    {
        InitializeComponent();
    }        

    private void button1_Click(object sender, EventArgs e)
    {
        Process process = new Process();
        process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

        process.StartInfo.FileName = Application.ExecutablePath;

        //Starts new process
        process.Start();

        //Wait for process main handle be acquired
        while (process.MainWindowHandle == IntPtr.Zero)            
            Thread.Sleep(1);            

        //Move window
        SetWindowPosFlags flags = SetWindowPosFlags.ShowWindow | SetWindowPosFlags.IgnoreResize | SetWindowPosFlags.IgnoreZOrder;
        SetWindowPos(process.MainWindowHandle, new IntPtr(0), this.Left + 10, this.Top + 10, 0, 0, flags);
    }

}

}

  • 0
    Спасибо за Ваш ответ. Работает ли это с ProcessWindowStyle.Hidden и CreateNoWindow = true? Я должен использовать их, иначе появится консоль R. Я подозреваю, что это может быть «главным окном», а запускаемый графический интерфейс Tk / Tcl является дочерним окном.
  • 0
    Нет, это не так. Это может быть проблемой, если «главным» окном для Tk / Tcl является окно консоли. Пожалуйста, попробуйте без тех же параметров, которые я предоставил, и скажите мне, перемещаются ли окна консоли или главное окно. Если это не так, нам нужно найти способ, чтобы получить ручку к желаемому окну.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню