能够在根据窗口大小调整坐标区,在某一具体x坐标附近的根的数据能用红色圆圈标注出来
图在哪里?什么数据标注点,请你把问题说清楚
// 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 消息处理程序
本文章使用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;
}
原创不易,转载请注明出处