使用VC++绘制曲线如何根据窗口大小调整

能够在根据窗口大小调整坐标区,在某一具体x坐标附近的根的数据能用红色圆圈标注出来

图在哪里?什么数据标注点,请你把问题说清楚

img

img


// sj8406220118_T1View.cpp: Csj8406220118T1View 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义,并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "sj8406220118_T1.h"
#endif

#include "sj8406220118_T1Doc.h"
#include "sj8406220118_T1View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// Csj8406220118T1View

IMPLEMENT_DYNCREATE(Csj8406220118T1View, CView)

BEGIN_MESSAGE_MAP(Csj8406220118T1View, CView)
    // 标准打印命令
    ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &Csj8406220118T1View::OnFilePrintPreview)
    ON_WM_CONTEXTMENU()
    ON_WM_RBUTTONUP()
END_MESSAGE_MAP()

// Csj8406220118T1View 构造/析构

Csj8406220118T1View::Csj8406220118T1View() noexcept
{
    // TODO: 在此处添加构造代码

}

Csj8406220118T1View::~Csj8406220118T1View()
{
}

BOOL Csj8406220118T1View::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: 在此处通过修改
    //  CREATESTRUCT cs 来修改窗口类或样式

    return CView::PreCreateWindow(cs);
}


double CalculateEquationValue(double x)
{
    double equationValue = sqrt(pow(x, 3.0)) - exp(x / 3.0);
    return equationValue;
}

double IterativeMethod(double initialGuess)
{
    double x = initialGuess;
    double epsilon = 0.0001; // 迭代法的收敛精度

    while (true)
    {
        double equationValue = CalculateEquationValue(x);

        if (fabs(equationValue) < epsilon)
            break;

        // 使用迭代公式更新x的值
        x = x - equationValue / (3.0 * pow(x, 2.0) - exp(x / 3.0) / 3.0);
    }

    return x;
}

// Csj8406220118T1View 绘图

void Csj8406220118T1View::OnDraw(CDC* pDC)
{
    Csj8406220118T1Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    // TODO: 在此处为本机数据添加绘制代码

    CRect rect;
    GetClientRect(&rect);

    // 计算坐标区域的宽度和高度
    mPlotWidth = rect.Width() * 3 / 4;
    mPlotHeight = rect.Height() * 3 / 4;

    // 创建一个内存设备上下文
    CDC memDC;
    memDC.CreateCompatibleDC(pDC);
    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    memDC.SelectObject(&bitmap);

    // 设置绘制属性
    memDC.SetBkMode(TRANSPARENT);
    memDC.SetTextColor(RGB(0, 0, 0));
    memDC.FillSolidRect(rect, RGB(255, 255, 255));

    // 绘制坐标轴
    int plotLeft = (rect.Width() - mPlotWidth) / 6;
    int plotRight = plotLeft + mPlotWidth;
    int plotTop = (rect.Height() - mPlotHeight) / 6;
    int plotBottom = plotTop + mPlotHeight;

    memDC.MoveTo(plotLeft, plotBottom);
    memDC.LineTo(plotRight, plotBottom);
    memDC.MoveTo(plotLeft, plotTop);
    memDC.LineTo(plotLeft, plotBottom);

    // 计算坐标变换的缩放因子和平移量
    double scaleX = mPlotWidth / (2.0 - 1.0);
    double scaleY = mPlotHeight / (sqrt(pow(2.0, 3.0)) - sqrt(pow(1.0, 3.0)));
    int offsetX = plotLeft;
    int offsetY = plotTop + mPlotHeight;

    // 绘制函数曲线 y(x) = sqrt(x^3)(绿色)
    CPen greenPen(PS_SOLID, 1, RGB(0, 255, 0));
    CPen* pOldPen = memDC.SelectObject(&greenPen);
    double stepSize = 0.01;

    for (double x = 1.0; x <= 2.0; x += stepSize)
    {
        double y = sqrt(pow(x, 3.0));
        int screenX = offsetX + static_cast<int>((x - 1.0) * scaleX);
        int screenY = offsetY - static_cast<int>((y - sqrt(pow(1.0, 3.0))) * scaleY);

        if (x == 1.0)
            memDC.MoveTo(screenX, screenY);
        else
            memDC.LineTo(screenX, screenY);
    }

    memDC.SelectObject(pOldPen);

    // 绘制函数曲线 f(x) = e^(x/3)(红色)
    CPen redPen(PS_SOLID, 1, RGB(255, 0, 0));
    pOldPen = memDC.SelectObject(&redPen);

    for (double x = 1.0; x <= 2.0; x += stepSize)
    {
        double y = exp(x / 3.0);
        int screenX = offsetX + static_cast<int>((x - 1.0) * scaleX);
        int screenY = offsetY - static_cast<int>((y - exp(1.0 / 3.0)) * scaleY);

        if (x == 1.0)
            memDC.MoveTo(screenX, screenY);
        else
            memDC.LineTo(screenX, screenY);
    }

    memDC.SelectObject(pOldPen);

    // 使用迭代法求方程的根
    double rootX = IterativeMethod(1.4);
    double rootY = sqrt(pow(rootX, 3.0));
    int screenX = offsetX + static_cast<int>((rootX - 1.0) * scaleX);
    int screenY = offsetY - static_cast<int>((rootY - sqrt(pow(1.0, 3.0))) * scaleY);

    // 绘制红色圈圈
    CPen redPen1(PS_SOLID, 1, RGB(255, 0, 0));
    CPen* pOldPen1 = memDC.SelectObject(&redPen);
    memDC.SelectStockObject(NULL_BRUSH);
    memDC.Ellipse(screenX - 5, screenY - 5, screenX + 5, screenY + 5);
    memDC.SelectObject(pOldPen);

    // 将内存设备上下文的内容绘制到屏幕上
    pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
}


// Csj8406220118T1View 打印


void Csj8406220118T1View::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
    AFXPrintPreview(this);
#endif
}

BOOL Csj8406220118T1View::OnPreparePrinting(CPrintInfo* pInfo)
{
    // 默认准备
    return DoPreparePrinting(pInfo);
}

void Csj8406220118T1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
    // TODO: 添加额外的打印前进行的初始化过程
}

void Csj8406220118T1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
    // TODO: 添加打印后进行的清理过程
}

void Csj8406220118T1View::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
    ClientToScreen(&point);
    OnContextMenu(this, point);
}

void Csj8406220118T1View::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
    theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// Csj8406220118T1View 诊断

#ifdef _DEBUG
void Csj8406220118T1View::AssertValid() const
{
    CView::AssertValid();
}

void Csj8406220118T1View::Dump(CDumpContext& dc) const
{
    CView::Dump(dc);
}

Csj8406220118T1Doc* Csj8406220118T1View::GetDocument() const // 非调试版本是内联的
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(Csj8406220118T1Doc)));
    return (Csj8406220118T1Doc*)m_pDocument;
}
#endif //_DEBUG


// Csj8406220118T1View 消息处理程序


  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/254727
  • 你也可以参考下这篇文章:VC++检查程序托盘图标是否掩藏到沙漏区域中(附源码)
  • 除此之外, 这篇博客: 用 VC++ 调用最小的浏览器内核创建一个简易的浏览器中的 教程说明 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 本文章使用VisualStudio里提供的VC++来进行演示,使用Miniblink不需要用到过多的操作,只要把下载好压缩包里的头文件wke.h复制到我们的工程目录下,在程序内部导入此头文件即可调用到Miniblink提供的API函数,因为Miniblink是以动态链接库的方式调用的,在我们运行程序之前还需要复制压缩包里的node.dll到程序项目生成目录下,wke.h头文件里会自动导入此库。

    需要注意的是调用Miniblink提供的接口时,绝对不能夸线程调用的,我们在窗口消息线程调用即可,如果一定要在其他线程调用,建议使用发送窗口消息(SendMessage,PostMessage)形式来进行调用即可,这不是Miniblink内核本身的问题,算是一种线程安全的基本常识吧。

    用Miniblink创建一个简易的浏览器非常简单,如果用到的功能单一,只是打开一个显示页面,用到以下几个API即可。

    API说明
    wkeInitialize导入动态链接库node.dll,初始化Miniblink的接口
    wkeCreateWebWindow创建浏览器窗口,返回可操作该页面的接口指针
    wkeOnWindowDestroy绑定浏览器窗口的销毁事件,用于处理程序的退出
    wkeGetWindowHandle通过操作指针(wkeWebView)来获取创建后的窗口句柄
    wkeMoveToCenter把浏览器窗口移动到屏幕中心的位置
    wkeShowWindow显示或隐藏创建后的浏览器窗口
    wkeLoadURL让浏览器窗口视图加载指定页面地址

    这里只介绍几个常用到的API,如果想知道更多其他的东西可以到官方页面查看更多API说明信息

    我们先用VisualStudio创建一个空的项目,项目名称为mb_simple_demo,位置可以选择自己常用的目录下即可。
    在这里插入图片描述
    项目创建完成后,因为我们的浏览器需要用到窗口界面,所以需要把我们的项目配置里的配置属性->链接器->系统->子系统修改成窗口属性,
    在这里插入图片描述
    做完以上步骤后我们就可以开始创建一个非常简单的浏览器了,在“源文件”筛选器下创建一个C++源码文件main.cpp
    在这里插入图片描述
    接下来源码部分非常简单,几十行代码即可完成创建了,是不是很方便呢?

    main.cpp

    //在下载好的Miniblink压缩包里可以找到此头文件,把其复制到我们的工程源码目录下即可
    //复制完成后,再把压缩文件下的node.dll复制到项目生成目录,Miniblink开发环境便完成搭建
    #include "wke.h"
    
    wkeWebView	G_WebView = NULL;		//Miniblink浏览器视图指针
    HWND		G_WindHandle = NULL;	//浏览器窗口的窗口句柄
    
    //消息循环分发
    void MessageLoop() {
    	MSG v_Message = { 0 };
    	while (GetMessage(&v_Message, NULL, 0, 0))
    	{
    		TranslateMessage(&v_Message);
    		DispatchMessage(&v_Message);
    	}
    }
    
    //浏览器窗口销毁回调函数,在行36处执行绑定到浏览器窗口后有效。
    void onWindowDestroy(wkeWebView webWindow, void* param) {
    	PostQuitMessage(0);
    }
    
    int __stdcall WinMain(
    	HINSTANCE hInstance,
    	HINSTANCE hPrevInstance,
    	LPSTR lpCmdLine,
    	int nCmdShow
    ) {
    	//这个API函数用于导入动态链接库node.dll,初始化Miniblink的接口
    	wkeInitialize();
    
    	//Miniblink接口初始化完成后,我们就可以直接开始创建一个简单的浏览器窗口
    	G_WebView = wkeCreateWebWindow(wkeWindowType::WKE_WINDOW_TYPE_POPUP, NULL, 0, 0, 1024, 700);
    
    	//绑定窗口销毁事件,用于退出整个程序
    	wkeOnWindowDestroy(G_WebView, onWindowDestroy, NULL);
    
    	//窗口创建完成后通过这个接口我们就可以获取到窗口句柄
    	G_WindHandle = wkeGetWindowHandle(G_WebView);
    
    	//调用此API把刚刚创建的浏览器创建移动到屏幕中间
    	wkeMoveToCenter(G_WebView);
    
    	//之后我们还需要调用此API把窗口显示下
    	wkeShowWindow(G_WebView, TRUE);
    
    	//这里让浏览器窗口打开我们指定的页面即可
    	wkeLoadURL(G_WebView, "https://www.csdn.net");
    
    	//运行Windows消息循环,处理与用户交互的消息,这里会阻塞直到浏览器窗口销毁后运行PostQuitMessage(0)执行程序最后的退出步骤
    	MessageLoop();
    
    	return 0;
    }
    

    原创不易,转载请注明出处

  • 您还可以看一下 大雄老师的从逆向视角看VC++面向对象特征 课程中的 逆向时如何定位虚函数表小节, 巩固相关知识点